net.lunikon.rethul.service.FileService.java Source code

Java tutorial

Introduction

Here is the source code for net.lunikon.rethul.service.FileService.java

Source

/*
 * Copyright (c) 2011 by Martin Simons.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package net.lunikon.rethul.service;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import net.lunikon.rethul.data.FileDAO;
import net.lunikon.rethul.data.StringsDAO;
import net.lunikon.rethul.model.File;
import net.lunikon.rethul.model.FileStatus;
import net.lunikon.rethul.model.LocalizedString;
import net.lunikon.rethul.model.Project;
import net.lunikon.rethul.util.SortedProperties;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

/**
 * FileService.
 * 
 * @author Martin Simons
 */
@Transactional
public class FileService {
    /**
     * The E_FILE_NAME_EXISTS.
     */
    public static final String E_FILE_NAME_EXISTS = "File.e.name.exists";

    /**
     * The fileDAO.
     */
    @Autowired
    private FileDAO fileDAO;

    /**
     * The stringsDAO.
     */
    @Autowired
    private StringsDAO stringsDAO;

    /**
     * Adds the given file name to the project.
     * 
     * @param project
     *            The project.
     * @param name
     *            The name of the file to create.
     * @throws ServiceException
     *             when a file by this name already exists.
     */
    public void create(Project project, String name) throws ServiceException {
        File file = fileDAO.getByProjectAndName(project, name);
        if (file != null)
            throw new ServiceException(E_FILE_NAME_EXISTS);

        file = new File(project, name);
        fileDAO.save(file);
    }

    /**
     * Reloads the master file. New keys are added. If a key value changes, the
     * corresponding translations are marked as pending. Keys that have dropped
     * from the master file are deleted in all translations.
     * 
     * @param file
     *            The file.
     * @return an array containing the number of affected keys/strings. [0] new
     *         keys added, [1] changed master values, [2] strings marked as
     *         pending, [3] keys removed, [4] strings deleted
     */
    public Object[] reloadMaster(File file) {
        // load properties
        Properties props = new Properties();
        try {
            FileInputStream is = new FileInputStream(FileStatus.getLanguageFilePath(file, null));
            props.load(is);
            is.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // load existing master strings from database and add them to a map
        List<LocalizedString> strings = stringsDAO.loadMasterStrings(file);
        Map<String, LocalizedString> existing = new HashMap<String, LocalizedString>(strings.size());
        for (LocalizedString ls : strings)
            existing.put(ls.getKey(), ls);

        // an array containing some counters that will be returned as the result
        Object[] results = new Object[5];

        // run through properties
        int added = 0, changed = 0;
        Set<String> pending = new HashSet<String>();
        for (String key : props.stringPropertyNames()) {
            // does key exist yet?
            LocalizedString value = existing.get(key);
            String masterValue = props.getProperty(key);
            if (value != null) {
                if (!value.getTranslation().equals(masterValue)) {
                    // mark key as pending
                    pending.add(key);
                    changed++;

                    // update master
                    value.setTranslation(masterValue);
                    stringsDAO.update(value);
                }
            } else {
                // create new key
                value = new LocalizedString(file, key, masterValue);
                stringsDAO.save(value);
                added++;
            }

            // remove from existing list
            existing.remove(key);
        }
        results[0] = added;
        results[1] = changed;

        // mark all strings that changed in master as pending for other locales
        results[2] = stringsDAO.markPending(file, pending);

        // delete strings that have dropped from the master
        results[3] = existing.size();
        results[4] = stringsDAO.deleteKeys(file, existing.keySet());

        return results;
    }

    /**
     * Loads a language file and writes its content to the corresponding file in
     * rethul. Only keys are imported that are also defined by the master. All
     * imported strings are marked as "pending".
     * 
     * @param file
     *            The file.
     * @param locale
     *            The locale.
     */
    public void reload(File file, Locale locale) {
        // first, load master keys
        Set<String> masterKeys = stringsDAO.loadMasterKeySet(file);

        // load properties from file
        Properties props = new Properties();
        try {
            String path = FileStatus.getLanguageFilePath(file, locale);
            FileInputStream is = new FileInputStream(path);
            props.load(is);
            is.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // add all values that exist in master
        for (String key : props.stringPropertyNames()) {
            if (!masterKeys.contains(key))
                continue;

            String value = props.getProperty(key);

            LocalizedString ls = new LocalizedString(file, key, value);
            ls.setLocale(locale);
            ls.setPending(true);
            stringsDAO.save(ls);
        }
    }

    public void writeOut(File file) {
        // load all completed strings
        List<LocalizedString> completed = stringsDAO.loadCompletedStrings(file);
        if (completed.isEmpty())
            return;

        // sort them into properties
        Map<Locale, SortedProperties> properties = new HashMap<Locale, SortedProperties>();
        for (LocalizedString string : completed) {
            Locale locale = string.getLocale();

            SortedProperties props = properties.get(locale);
            if (props == null) {
                props = new SortedProperties();
                properties.put(locale, props);
            }

            props.setProperty(string.getKey(), string.getTranslation());
        }

        // write out files
        for (Locale locale : properties.keySet()) {
            Properties props = properties.get(locale);

            String filename = FileStatus.getLanguageFilePath(file, locale);
            try {
                FileOutputStream out = new FileOutputStream(filename);
                props.store(out, null);

                out.close();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }
}