org.jahia.ajax.gwt.helper.GWTResourceBundleUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.ajax.gwt.helper.GWTResourceBundleUtils.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.ajax.gwt.helper;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;

import javax.jcr.RepositoryException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.jahia.ajax.gwt.client.data.GWTJahiaValueDisplayBean;
import org.jahia.ajax.gwt.client.data.GWTResourceBundle;
import org.jahia.ajax.gwt.client.data.GWTResourceBundleEntry;
import org.jahia.ajax.gwt.client.data.node.GWTJahiaNode;
import org.jahia.ajax.gwt.client.service.GWTJahiaServiceException;
import org.jahia.api.Constants;
import org.jahia.services.content.JCRContentUtils;
import org.jahia.services.content.JCRNodeWrapper;
import org.jahia.services.content.JCRSessionWrapper;
import org.jahia.services.content.nodetypes.NodeTypeRegistry;
import org.jahia.utils.LanguageCodeConverters;
import org.jahia.utils.Patterns;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper class for populating {@link GWTResourceBundle} data in the {@link GWTJahiaNode} instance.
 * 
 * @author Sergiy Shyrkov
 */
public final class GWTResourceBundleUtils {

    /**
     * Unicode escaping utility. Code from the ResourceBundle Editor Eclipse plugin (http://eclipse-rbe.sourceforge.net)
     */
    private static final class EscapeUtils {

        private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
                'D', 'E', 'F' };

        static String convertUnicodeToEncoded(String str) {
            int len = str.length();
            StringBuilder outBuffer = new StringBuilder(len * 2);

            for (int x = 0; x < len; x++) {
                char aChar = str.charAt(x);
                if ((aChar < ' ') || (aChar > '~')) {
                    outBuffer.append('\\');
                    outBuffer.append('u');
                    outBuffer.append(toHex(aChar >> '\f' & 0xF));
                    outBuffer.append(toHex(aChar >> '\b' & 0xF));
                    outBuffer.append(toHex(aChar >> '\004' & 0xF));
                    outBuffer.append(toHex(aChar & 0xF));
                } else {
                    outBuffer.append(aChar);
                }
            }
            return outBuffer.toString();
        }

        private static char toHex(int nibble) {
            char hexChar = HEX_DIGITS[(nibble & 0xF)];
            return Character.toLowerCase(hexChar);
        }
    }

    private static Logger logger = LoggerFactory.getLogger(GWTResourceBundleUtils.class);

    private static String getAsString(String lang, GWTResourceBundle bundle) {
        StringBuilder out = new StringBuilder(512);
        for (GWTResourceBundleEntry entry : bundle.getEntries()) {
            String value = entry.getValue(lang);
            if (StringUtils.isEmpty(value)) {
                // we do not write entries with empty values
                continue;
            }
            out.append(entry.getKey()).append("=").append(EscapeUtils.convertUnicodeToEncoded(value)).append("\n");
        }

        return out.toString();
    }

    private static String getLanguageCode(String resourceBundleFileName) {
        String name = StringUtils.substringBeforeLast(resourceBundleFileName, ".properties");
        String lang = GWTResourceBundle.DEFAULT_LANG;
        if (name.contains("_")) {
            String[] parts = Patterns.UNDERSCORE.split(name);
            int l = parts.length;
            if (l == 2) {
                lang = parts[1];
            } else if (l == 3) {
                lang = parts[1] + "_" + parts[2];
            } else if (l >= 4) {
                lang = parts[l - 3] + "_" + parts[l - 2] + "_" + parts[l - 1];
            }
        }

        return lang;
    }

    private static boolean isValidKey(String key) {
        return key != null && key.length() > 0 && key.indexOf('<') == -1 && key.indexOf('=') == -1
                && key.indexOf('>') == -1;
    }

    public static GWTResourceBundle load(JCRNodeWrapper node, Locale uiLocale) {
        GWTResourceBundle gwtBundle = null;
        long timer = System.currentTimeMillis();
        try {
            boolean isFile = false;
            if (!(isFile = node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FILE))
                    && !node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FOLDER)) {
                return null;
            }

            gwtBundle = new GWTResourceBundle();

            Set<String> languages = new HashSet<String>();
            List<JCRNodeWrapper> rbFileNodes = JCRContentUtils.getChildrenOfType(isFile ? node.getParent() : node,
                    Constants.JAHIANT_RESOURCEBUNDLE_FILE);
            for (JCRNodeWrapper rbFileNode : rbFileNodes) {
                populate(gwtBundle, rbFileNode, languages);
            }
            for (GWTResourceBundleEntry entry : gwtBundle.getEntryMap().values()) {
                for (String l : languages) {
                    if (entry.getValues().get(l) == null) {
                        // add the language to that entry
                        entry.setValue(l, null);
                    }
                }
            }
            // if empty, define a default bundle
            if (gwtBundle.getEntries().isEmpty()) {
                gwtBundle.setName(node.getResolveSite().getTemplatePackage().getId());
                gwtBundle.setValue("<empty>", GWTResourceBundle.DEFAULT_LANG, null);
            }

            // load available languages
            List<GWTJahiaValueDisplayBean> availableLocales = new ArrayList<GWTJahiaValueDisplayBean>();
            for (Locale l : LanguageCodeConverters.getSortedLocaleList(uiLocale)) {
                availableLocales.add(new GWTJahiaValueDisplayBean(l.toString(),
                        StringUtils.capitalize(l.getDisplayName(uiLocale))));
            }
            gwtBundle.setAvailableLanguages(availableLocales);

            if (logger.isDebugEnabled()) {
                logger.debug("Loaded resource bundle for node {} in {} ms", node.getPath(),
                        System.currentTimeMillis() - timer);
            }
        } catch (RepositoryException e) {
            logger.error(e.getMessage(), e);
        }

        return gwtBundle;
    }

    public static void lock(JCRNodeWrapper node) {
        try {
            boolean isFile = false;
            if (!(isFile = node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FILE))
                    && !node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FOLDER)) {
                return;
            }

            final JCRNodeWrapper parent = isFile ? node.getParent() : node;
            List<JCRNodeWrapper> rbFileNodes = JCRContentUtils.getChildrenOfType(parent,
                    Constants.JAHIANT_RESOURCEBUNDLE_FILE);
            for (JCRNodeWrapper rbFileNode : rbFileNodes) {
                rbFileNode.lockAndStoreToken("engine");
            }
            parent.lockAndStoreToken("engine");
        } catch (RepositoryException e) {
            logger.error(e.getMessage(), e);
        }

        return;
    }

    private static void populate(GWTResourceBundle gwtBundle, JCRNodeWrapper node, Set<String> languages) {

        String name = StringUtils.substringBeforeLast(node.getName(), ".properties");
        String lang = GWTResourceBundle.DEFAULT_LANG;
        if (name.contains("_")) {
            lang = getLanguageCode(name);
            if (gwtBundle.getName() == null) {
                name = StringUtils.substringBeforeLast(StringUtils.substringBeforeLast(name, lang), "_");
            }
        }
        if (gwtBundle.getName() == null) {
            gwtBundle.setName(name);
        }
        languages.add(lang);

        InputStream is = null;
        try {
            is = node.getFileContent().downloadFile();
            Properties p = new Properties();
            p.load(is);
            for (Object keyObj : p.keySet()) {
                String key = keyObj.toString();
                if (isValidKey(key)) {
                    gwtBundle.setValue(key, lang, p.getProperty(key));
                }
            }
        } catch (IOException e) {
            logger.error("Error reading content of the " + node.getPath() + " node as a properties file. Cause: "
                    + e.getMessage(), e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    public static boolean store(GWTJahiaNode gwtNode, GWTResourceBundle bundle, JCRSessionWrapper session)
            throws GWTJahiaServiceException {
        boolean needPermissionReload = false;
        try {
            JCRNodeWrapper node = session.getNode(
                    gwtNode.isFile() ? StringUtils.substringBeforeLast(gwtNode.getPath(), "/") : gwtNode.getPath());

            Map<String, JCRNodeWrapper> nodesByLanguage = new HashMap<String, JCRNodeWrapper>();
            for (JCRNodeWrapper rbFileNode : JCRContentUtils.getChildrenOfType(node, "jnt:propertiesFile")) {
                nodesByLanguage.put(getLanguageCode(rbFileNode.getName()), rbFileNode);
            }

            for (String lang : bundle.getLanguages()) {
                JCRNodeWrapper current = nodesByLanguage.remove(lang);
                InputStream is = null;
                try {
                    is = new ByteArrayInputStream(getAsString(lang, bundle).getBytes("ISO-8859-1"));
                    if (current == null) {
                        // new language
                        logger.debug("Processing new resource bundle for language '{}'", lang);
                        String bundleName;
                        if (StringUtils.equals(lang, GWTResourceBundle.DEFAULT_LANG)) {
                            bundleName = bundle.getName() + ".properties";
                        } else {
                            bundleName = bundle.getName() + "_" + lang + ".properties";
                        }
                        node.uploadFile(bundleName, is, "text/plain");
                    } else {
                        // updating existing language
                        logger.debug("Processing resource bundle {} for language '{}'", current.getPath(), lang);
                        current.getFileContent().uploadFile(is, "text/plain");
                    }
                } catch (UnsupportedEncodingException e) {
                    throw new IllegalArgumentException(e.getMessage(), e);
                } finally {
                    IOUtils.closeQuietly(is);
                }
            }

            // removing deleted languages if any
            for (Iterator<JCRNodeWrapper> iterator = nodesByLanguage.values().iterator(); iterator.hasNext();) {
                JCRNodeWrapper toDelete = iterator.next();
                logger.debug("Removing resource bundle node {}", toDelete.getPath());
                toDelete.remove();
            }
            ResourceBundle.clearCache();
            NodeTypeRegistry.getInstance().flushLabels();
            needPermissionReload = !node.getResolveSite().getLanguages().containsAll(bundle.getLanguages());
            node.getResolveSite().setLanguages(bundle.getLanguages());
        } catch (RepositoryException e) {
            logger.error(e.getMessage(), e);
            throw new GWTJahiaServiceException(e.getMessage());
        }
        return needPermissionReload;
    }

    public static void unlock(JCRNodeWrapper node) {
        try {
            boolean isFile = false;
            if (!(isFile = node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FILE))
                    && !node.isNodeType(Constants.JAHIANT_RESOURCEBUNDLE_FOLDER)) {
                return;
            }

            final JCRNodeWrapper parent = isFile ? node.getParent() : node;
            List<JCRNodeWrapper> rbFileNodes = JCRContentUtils.getChildrenOfType(parent,
                    Constants.JAHIANT_RESOURCEBUNDLE_FILE);
            for (JCRNodeWrapper rbFileNode : rbFileNodes) {
                if (rbFileNode.isLocked()) {
                    rbFileNode.unlock("engine");
                }
            }
            if (parent.isLocked()) {
                parent.unlock("engine");
            }
        } catch (RepositoryException e) {
            logger.error(e.getMessage(), e);
        }

        return;
    }

    private GWTResourceBundleUtils() {
        super();
    }
}