/* =============================================================================== * * Part of the InfoGlue Content Management Platform (www.infoglue.org) * * =============================================================================== * * Copyright (C) * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 2, as published by the * Free Software Foundation. See the file LICENSE.html for more information. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY, including 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. / 59 Temple * Place, Suite 330 / Boston, MA 02111-1307 / USA. * * =============================================================================== */ package org.infoglue.cms.controllers.kernel.impl.simple; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; import org.apache.log4j.Logger; import org.exolab.castor.jdo.Database; import org.exolab.castor.jdo.OQLQuery; import org.exolab.castor.jdo.QueryResults; import org.infoglue.cms.entities.content.DigitalAsset; import org.infoglue.cms.entities.content.DigitalAssetVO; import org.infoglue.cms.entities.content.impl.simple.DigitalAssetImpl; import org.infoglue.cms.entities.kernel.BaseEntityVO; import org.infoglue.cms.exception.ConstraintException; import org.infoglue.cms.exception.SystemException; import org.infoglue.cms.util.CmsPropertyHandler; import org.infoglue.cms.util.StringManager; import org.infoglue.cms.util.StringManagerFactory; import org.infoglue.deliver.util.NullObject; import org.infoglue.deliver.util.Timer; /** * @author Mattias Bogeblad */ public class LabelController extends BaseController implements StringManager { private final static Logger logger = Logger.getLogger(LabelController.class.getName()); private Locale locale = Locale.getDefault(); private static Map<String,LabelController> controllers = new HashMap<String,LabelController>(); private LabelController() { } private LabelController(Locale locale) { this.locale = locale; } /** * Factory method */ public static LabelController getController(Locale locale) { LabelController controller = controllers.get("" + locale.getLanguage()); if(controller == null) { controller = new LabelController(locale); controllers.put("" + locale.getLanguage(), controller); } return controller; } /** * This method deletes a digital asset in the database. */ public static void delete(Integer digitalAssetId) throws ConstraintException, SystemException { deleteEntity(DigitalAssetImpl.class, digitalAssetId); } public List<Locale> getAvailableTranslations() { List<Locale> translations = new ArrayList<Locale>(); try { File file = new File(CmsPropertyHandler.getContextRootPath() + File.separator + "translations"); File[] translationFiles = file.listFiles(); for(int i=0; i<translationFiles.length; i++) { File translation = translationFiles[i]; if(!translation.isDirectory()) { String name = translation.getName(); if(name.startsWith("PresentationStrings_")) { String localeName = name.substring("PresentationStrings_".length(), name.indexOf(".")); try { Locale locale = new Locale(localeName); translations.add(locale); } catch (Exception e) { logger.error("Error getting locale for " + localeName + ":" + e.getMessage(), e); } } } } } catch (Exception e) { logger.error("Could not get themes: " + e.getMessage(), e); } return translations; } private static Map<String,Object> cachedBundles = new HashMap<String,Object>(); private static Map<String,String> cachedLabels = new HashMap<String,String>(); public String getLocalizedString(Locale locale, String key) { return getLocalizedString(locale, key, false); } public String getLocalizedString(Locale locale, String key, boolean forceSystemBundle) { Timer t = new Timer(); String value = null; String valueCacheKey = "" + locale + "_" + key; String cachedLabel = cachedLabels.get(valueCacheKey); //logger.info("valueCacheKey:" + valueCacheKey + " gave " + cachedLabel); if(cachedLabel != null) { //t.printElapsedTime("Getting getLocalizedString..."); return cachedLabel; } String cacheKey = "" + locale; Object cachedBundle = cachedBundles.get(cacheKey); //logger.info("cacheKey:" + cacheKey + " gave " + cachedBundle); ResourceBundle resourceBundle = null; //t.printElapsedTime("1"); if(!(cachedBundle instanceof NullObject)) { //logger.info("Not a NullObject.." + cachedBundle); if(cachedBundle != null) { //logger.info("Not null:" + cachedBundle.getClass().getName()); resourceBundle = (ResourceBundle)cachedBundle; } else { //logger.info("A null:" + cachedBundle); try { //t.printElapsedTime("1.1"); resourceBundle = getResourceBundle(locale); //t.printElapsedTime("1.2"); if(resourceBundle == null) { resourceBundle = checkForResourceBundleAsset(locale); //t.printElapsedTime("1.3"); } if(resourceBundle == null) cachedBundles.put(cacheKey, new NullObject()); else cachedBundles.put(cacheKey, resourceBundle); } catch (Exception e) { logger.error("Could not get value from bundle:" + e.getMessage()); if(logger.isDebugEnabled()) logger.debug("Could not get value from bundle:" + e.getMessage(), e); } } } //t.printElapsedTime("2"); if(resourceBundle != null) { try { if(resourceBundle.containsKey(key)) value = resourceBundle.getString(key); else value = getLocalizedSystemString(locale, key, true); } catch (MissingResourceException e) { logger.error("Missing key: " + e.getMessage()); //value = getLocalizedSystemString(locale, key, true); value = "MISSING LABEL: " + key; } } //t.printElapsedTime("3"); if(value == null || value.equals("")) value = getLocalizedSystemString(locale, key); if(value != null) cachedLabels.put(valueCacheKey, value); //t.printElapsedTime("Getting getLocalizedString..."); return value; } public String getLocalizedString(Locale locale, String key, Object[] args) { return getLocalizedString(locale, key, args, false); } public String getLocalizedString(Locale locale, String key, Object[] args, boolean forceSystemBundle) { Timer t = new Timer(); String value = null; String cacheKey = "" + locale; Object cachedBundle = cachedBundles.get(cacheKey); ResourceBundle resourceBundle = null; //t.printElapsedTime("1"); if(!(cachedBundle instanceof NullObject)) { //logger.info("Not a NullObject.." + cachedBundle); if(cachedBundle != null) { //logger.info("Not null:" + cachedBundle.getClass().getName()); resourceBundle = (ResourceBundle)cachedBundle; } else { //logger.info("A null:" + cachedBundle); try { //t.printElapsedTime("1.1"); resourceBundle = getResourceBundle(locale); //t.printElapsedTime("1.2"); if(resourceBundle == null) { resourceBundle = checkForResourceBundleAsset(locale); //t.printElapsedTime("1.3"); } if(resourceBundle == null) cachedBundles.put(cacheKey, new NullObject()); else cachedBundles.put(cacheKey, resourceBundle); } catch (Exception e) { logger.error("Could not get value from bundle:" + e.getMessage(), e); } } } //t.printElapsedTime("2"); //logger.info("\n\n:args:" + args[0]); if(resourceBundle != null) { try { value = MessageFormat.format(resourceBundle.getString(key), args); } catch (MissingResourceException e) { logger.info("Missing label: " + e.getMessage()); if(!forceSystemBundle) value = getLocalizedString(locale, key, args, true); } } //t.printElapsedTime("3"); if(value == null || value.equals("")) value = getLocalizedSystemString(locale, key, args); //t.printElapsedTime("Getting getLocalizedString..."); //System.out.println("value: " + value); return value; } private String getLocalizedSystemString(Locale locale, String key) { StringManager stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", locale); return stringManager.getString(key); /* try { return stringManager.getString(key); } catch (Throwable t) { logger.info("There was no string:" + key + " in locale:" + locale); stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", Locale.ENGLISH); return stringManager.getString(key); } */ } private String getLocalizedSystemString(Locale locale, String key, Object arg1) { StringManager stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", locale); return stringManager.getString(key, arg1); /* try { return stringManager.getString(key, arg1); } catch (Throwable t) { logger.info("There was no string:" + key + " in locale:" + locale); stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", Locale.ENGLISH); return stringManager.getString(key, arg1); } */ } private String getLocalizedVariabledSystemString(Locale locale, String key, Object arg1, Object arg2) { StringManager stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", locale); return stringManager.getString(key, arg1, arg2); /* try { return stringManager.getString(key, arg1, arg2); } catch (Throwable t) { logger.info("There was no string:" + key + " in locale:" + locale); stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", Locale.ENGLISH); return stringManager.getString(key, arg1, arg2); } */ } private String getLocalizedSystemString(Locale locale, String key, Object[] args) { StringManager stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", locale); return stringManager.getString(key, args); /* try { return stringManager.getString(key, arg1, arg2); } catch (Throwable t) { logger.info("There was no string:" + key + " in locale:" + locale); stringManager = StringManagerFactory.getPresentationStringManager("org.infoglue.cms.applications", Locale.ENGLISH); return stringManager.getString(key, arg1, arg2); } */ } public ResourceBundle getResourceBundle(Locale locale) { ResourceBundle resourceBundle = null; //String javaVersion = System.getProperty("java.version", "1.5"); File file = new File(CmsPropertyHandler.getContextRootPath() + File.separator + "translations" + File.separator + "PresentationStrings_" + locale.getLanguage() + ".properties"); if(file.exists()) { try { //if(javaVersion.equalsIgnoreCase("1.3") || javaVersion.equalsIgnoreCase("1.4") || javaVersion.equalsIgnoreCase("1.5")) resourceBundle = new PropertyResourceBundle(new FileInputStream(file)); //else //resourceBundle = new PropertyResourceBundle(new FileReader(file)); } catch (Exception e) { logger.error("Could not load custom resource bundle for locale " + locale.getLanguage() + ":" + e.getMessage(), e); } } return resourceBundle; } public static DigitalAsset create(DigitalAssetVO digitalAssetVO, InputStream is) throws SystemException { Database db = CastorDatabaseService.getDatabase(); DigitalAsset digitalAsset = null; beginTransaction(db); try { digitalAsset = new DigitalAssetImpl(); digitalAsset.setValueObject(digitalAssetVO); digitalAsset.setAssetBlob(is); db.create(digitalAsset); commitTransaction(db); } catch (Exception e) { logger.error("An error occurred so we should not complete the transaction:" + e, e); rollbackTransaction(db); throw new SystemException(e.getMessage()); } return digitalAsset; } public static List getDigitalAssetByName(String name) throws SystemException { Database db = CastorDatabaseService.getDatabase(); List contents = new ArrayList(); beginTransaction(db); try { contents = getDigitalAssetByName(name, db); commitTransaction(db); } catch (Exception e) { logger.error("An error occurred so we should not complete the transaction:" + e, e); rollbackTransaction(db); throw new SystemException(e.getMessage()); } return contents; } public static List getDigitalAssetByName(String name, Database db) throws SystemException, Exception { List contents = new ArrayList(); OQLQuery oql = db.getOQLQuery("SELECT c FROM org.infoglue.cms.entities.content.impl.simple.DigitalAssetImpl c WHERE c.assetContentType = $1 AND c.assetFileName = $2"); oql.bind("text/infoglue-translation"); oql.bind(name); QueryResults results = oql.execute(Database.READONLY); while (results.hasMore()) { contents.add(results.next()); } results.close(); oql.close(); return contents; } public ResourceBundle checkForResourceBundleAsset(Locale locale) throws SystemException { ResourceBundle resourceBundle = null; Database db = CastorDatabaseService.getDatabase(); try { db.begin(); File file = new File(CmsPropertyHandler.getContextRootPath() + File.separator + "translations" + File.separator + "PresentationStrings_" + locale.getLanguage() + ".properties"); List assets = getDigitalAssetByName(file.getName(), db); //logger.info("assets:" + assets); Iterator assetsIterator = assets.iterator(); if(assetsIterator.hasNext()) { File translationsDir = new File(CmsPropertyHandler.getContextRootPath() + File.separator + "translations"); //logger.info("translationsDir:" + translationsDir); DigitalAsset da = (DigitalAsset)assetsIterator.next(); String themeName = da.getAssetFileName(); //logger.info("themeName:" + themeName); File presentationStringFile = new File(CmsPropertyHandler.getContextRootPath() + File.separator + "translations" + File.separator + da.getAssetFileName()); logger.info("Caching " + presentationStringFile + " at " + translationsDir); InputStream is = da.getAssetBlob(); FileOutputStream os = new FileOutputStream(presentationStringFile); BufferedOutputStream bos = new BufferedOutputStream(os); int num = copyStream(is, bos); bos.close(); os.close(); is.close(); resourceBundle = getResourceBundle(locale); //logger.info("Checking resourceBundle: " + resourceBundle); } } catch(Exception e) { logger.error("An error occurred when caching theme:" + e.getMessage()); } finally { try { db.commit(); db.close(); } catch (Exception e) { logger.error("Error closing db: " + e.getMessage()); } } return resourceBundle; } private static int copyStream(InputStream is, OutputStream os) throws IOException { int total = 0; byte[] buffer = new byte[1024]; int length = 0; while ((length = is.read(buffer)) >= 0) { os.write(buffer, 0, length); total += length; } os.flush(); return total; } /** * This is a method that gives the user back an newly initialized ValueObject for this entity that the controller * is handling. */ public BaseEntityVO getNewVO() { return null /*new ContentTypeDefinitionVO()*/; } public String getString(String key) { return getLocalizedString(this.locale, key); } public String getString(String key, Object[] args) { return getLocalizedString(this.locale, key, args); } public String getString(String key, Object arg) { return getLocalizedString(this.locale, key, arg); } public String getString(String key, Object arg1, Object arg2) { return getLocalizedString(this.locale, key, arg1, arg2); } public String getString(String key, Object arg1, Object arg2, Object arg3) { return getLocalizedString(this.locale, key, arg1, arg2, arg3); } public String getLocalizedString(String packageName, String key, Object[] args) { StringManager stringManager = StringManagerFactory.getPresentationStringManager(packageName, locale); return stringManager.getString(key, args); } public String getLocalizedString(String packageName, String key, Object[] args, ClassLoader classLoader) { StringManager stringManager = StringManagerFactory.getPresentationStringManager(packageName, locale, classLoader); return stringManager.getString(key, args); } }