com.adito.language.LanguagePackManager.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.language.LanguagePackManager.java

Source

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  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 2 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, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.adito.language;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.adito.boot.ContextHolder;
import com.adito.boot.SystemProperties;
import com.adito.boot.Util;

/**
 * Singleton responsible for managing registered <i>Language Packs</i> and
 * translation categories.
 * <p>
 * Internally, two lists of categories are maintained, one from resources called
 * <i>ApplicationResources.properties</i> automatically detected via the class
 * path and two from those registered via
 * {@link #registerCategory(LanguageCategory)}.
 * 
 * @see LanguagePackDefinition
 * @see LanguageCategory
 */
public class LanguagePackManager {

    final static Log log = LogFactory.getLog(LanguagePackManager.class);

    // Private instance variables
    private Map<String, LanguagePackDefinition> languagePackDefinitions;
    private List<LanguageCategory> detectedCategories;
    private Hashtable<String, LanguageCategory> detectedHaCategories;
    private List<LanguageCategory> categories;
    private Hashtable<String, LanguageCategory> haCategories;
    private URL[] classpath;

    // Private statics
    private static LanguagePackManager instance;

    /**
     * Although this call is used as a singleton, it has this package 
     * protected constructor for junit tests.
     */
    public LanguagePackManager() {
        super();
        languagePackDefinitions = new HashMap<String, LanguagePackDefinition>();
        categories = new ArrayList<LanguageCategory>();
        haCategories = new Hashtable<String, LanguageCategory>();
    }

    /**
     * Register a new category. This will always be available regardless of
     * whether or not it is found on the classpath. This can be used by plugins
     * to add categories for resource files that do not use the Adito
     * wide <i>ApplicationResources.properties</i> resource name (e.g.
     * resources for audit reports).
     * 
     * @param category category
     */
    public void registerCategory(LanguageCategory category) {
        categories.add(category);
        haCategories.put(category.getId(), category);
    }

    /**
     * Add a new language pack definition
     * 
     * @param def language pack definition
     */
    public void addLanguagePackDefinition(LanguagePackDefinition def) {
        log.info("Adding new language pack '" + def.getName() + "'");
        if (def.getExtensionDescriptor() != null) {
            log.info("Pack requires host version "
                    + def.getExtensionDescriptor().getApplicationBundle().getRequiredHostVersion());
        }
        languagePackDefinitions.put(def.getName(), def);
    }

    /**
     * Remove a language pack definition
     * 
     * @param def language pack definition
     */
    public void removeLanguagePack(LanguagePackDefinition def) {
        log.info("Removing language pack '" + def.getName() + "'");
        languagePackDefinitions.remove(def.getName());
    }

    /**
     * Get an instance of the language manager.
     * 
     * @return language manager
     */
    public static LanguagePackManager getInstance() {
        if (instance == null) {
            instance = new LanguagePackManager();
        }
        return instance;
    }

    /**
     * Get an iteration of all available {@link LanguagePackDefinition} objects
     * registered.
     * 
     * @return registered language pack definitions
     */
    public Iterator packDefinitions() {
        return languagePackDefinitions.values().iterator();
    }

    /**
     * Get an iteration of all available {@link Language} objects
     * If systemPropertiesFiler is true
     * the system check if some language are wanted to be hiddend. 
     * 
     * @param systemPropertiesFiler
     * @return languagePackDefinitions
     */
    public Iterator languages(boolean systemPropertiesFiler) {
        List<String> hiddenLanguagesList = new ArrayList<String>();
        if (systemPropertiesFiler) {
            String hiddenLanguages = SystemProperties.get("adito.hiddenLanguages", "");
            StringTokenizer t = new StringTokenizer(hiddenLanguages, ",");
            while (t.hasMoreTokens()) {
                hiddenLanguagesList.add(t.nextToken());
            }
        }
        List<Language> l = new ArrayList<Language>();
        for (Iterator i = languagePackDefinitions.values().iterator(); i.hasNext();) {
            LanguagePackDefinition def = (LanguagePackDefinition) i.next();
            for (Iterator j = def.languages(); j.hasNext();) {
                Language lang = (Language) j.next();
                if (!l.contains(lang)) {
                    if (!systemPropertiesFiler || !hiddenLanguagesList
                            .contains(def.getExtensionDescriptor() != null ? def.getName() : lang.getCode())) {
                        l.add(lang);
                    }
                }
            }
        }
        Collections.sort(l);
        return l.iterator();
    }

    /**
     * Get an iteration of all available {@link Language} objects
     * 
     * @return languagePackDefinitions
     */
    public Iterator languages() {
        return languages(false);
    }

    /**
     * Get all internationalisation categories. This includes all categories
     * registered using {@link #registerCategory(LanguageCategory)} and all
     * those found by looking for ApplicationResources.properties files in the
     * classpath.
     * <p>
     * This method returns a list of objects of type {@link LanguageCategory}.
     * <p>
     * The first call to this method may take some time as all JARS and class
     * directories will be scanned.
     * 
     * @return language category object
     * @throws IOException
     */
    public List<LanguageCategory> getCategories() throws IOException {
        checkCategories();
        List<LanguageCategory> l = new ArrayList<LanguageCategory>();
        l.addAll(detectedCategories);
        l.addAll(categories);
        return l;
    }

    synchronized void checkCategories() throws IOException {
        boolean classpathChanged = false;
        if (classpath != null) {
            URL[] newClasspath = ContextHolder.getContext().getContextLoaderClassPath();
            if (classpathDiffer(classpath, newClasspath)) {
                classpath = newClasspath;
                classpathChanged = true;
            }
        } else {
            classpath = ContextHolder.getContext().getContextLoaderClassPath();
        }
        if (detectedCategories == null || classpathChanged) {
            log.info("Scanning classpath for default message resources");
            detectedCategories = new ArrayList<LanguageCategory>();
            detectedHaCategories = new Hashtable<String, LanguageCategory>();
            for (int i = 0; i < classpath.length; i++) {
                log.debug("Scanning " + classpath[i]);
                if (classpath[i].getProtocol().equals("file")) {
                    if (classpath[i].getPath().endsWith(".jar")) {
                        addFileJarCategory(classpath[i]);
                    } else {
                        addFileDirectoryCategory(classpath[i]);
                    }
                }
            }
        }
    }

    boolean classpathDiffer(URL[] classpath, URL[] newClasspath) {
        if (classpath.length != newClasspath.length) {
            return true;
        }
        for (int i = 0; i < classpath.length; i++) {
            if (!classpath[i].equals(newClasspath[i])) {
                return true;
            }
        }
        return false;
    }

    /**
     * Get all internationalisation categories. This includes all categories
     * registered using {@link #registerCategory(LanguageCategory)} and all
     * those found by looking for ApplicationResources.properties files in the
     * classpath.
     * <p>
     * This method returns a Hashtable of objects of type
     * {@link LanguageCategory}.
     * <p>
     * The first call to this method may take some time as all JARS and class
     * directories will be scanned.
     * 
     * @return language category object
     * @throws IOException
     */
    public Hashtable getHaCategories() throws IOException {
        checkCategories();
        Hashtable<String, LanguageCategory> all = new Hashtable<String, LanguageCategory>();
        all.putAll(detectedHaCategories);
        all.putAll(haCategories);
        return all;
    }

    void addFileDirectoryCategory(URL url) throws IOException {
        File p = new File(Util.urlDecode(url.getPath()));
        List<File> files = new ArrayList<File>();
        findFile(p, "ApplicationResources.properties", files);
        for (Iterator it = files.iterator(); it.hasNext();) {
            File f = (File) it.next();
            String path = f.getAbsolutePath().substring(p.getAbsolutePath().length() + 1).replace("\\", "/");
            InputStream in = null;
            try {
                String name = path;
                String resourceBundleId = path;
                int idx = name.lastIndexOf('/');
                if (idx != -1) {
                    resourceBundleId = name.substring(0, idx).replace('/', '.');
                    name = name.substring(idx + 1);
                }
                in = new FileInputStream(f);
                LanguageCategory category = new LanguageCategory(in, url, path, resourceBundleId);
                if (!detectedHaCategories.containsKey(category.getId())) {
                    detectedCategories.add(category);
                    detectedHaCategories.put(category.getId(), category);
                }
            } finally {
                Util.closeStream(in);
            }
        }

    }

    void addFileJarCategory(URL url) throws IOException {

        InputStream in = null;
        try {
            File f = new File(Util.urlDecode(url.getPath()));
            if (!f.exists()) {
                return;
            }
            in = new FileInputStream(Util.urlDecode(url.getPath()));
            ZipInputStream zin = new ZipInputStream(in);
            while (true) {
                ZipEntry entry = zin.getNextEntry();
                if (entry == null) {
                    break;
                }
                String path = entry.getName();
                String name = path;
                String resourceBundleId = path;
                int idx = name.lastIndexOf('/');
                if (idx != -1) {
                    resourceBundleId = name.substring(0, idx).replace('/', '.');
                    ;
                    name = name.substring(idx + 1);
                }
                if (name.equals("ApplicationResources.properties")) {
                    LanguageCategory category = new LanguageCategory(zin, url, path, resourceBundleId);
                    if (!detectedHaCategories.containsKey(category.getId())) {
                        detectedCategories.add(category);
                        detectedHaCategories.put(category.getId(), category);
                    }
                }
            }
        } finally {
            Util.closeStream(in);
        }

    }

    /**
      * Get a language pack given its name (e.g. adito-language-fr).
      * <code>null</code> will be returned if no such language pack exists.
      * 
      * @param name name
      * @return language pack
      */
    public LanguagePackDefinition getLanguagePack(String name) {
        return (LanguagePackDefinition) languagePackDefinitions.get(name);
    }

    void findFile(File dir, String name, List<File> files) {
        File[] l = dir.listFiles();
        for (int i = 0; l != null && i < l.length; i++) {
            if (l[i].isDirectory()) {
                findFile(l[i], name, files);
            } else if (l[i].isFile() && l[i].getName().equals(name)) {
                files.add(l[i]);
            }
        }
    }
}