Coverage Report - net.fckeditor.localization.LocalizedMessages
 
Classes in this File Line Coverage Branch Coverage Complexity
LocalizedMessages
0%
0/86
0%
0/24
1,727
 
 1  
 /*
 2  
  * FCKeditor - The text editor for Internet - http://www.fckeditor.net
 3  
  * Copyright (C) 2004-2010 Frederico Caldeira Knabben
 4  
  * 
 5  
  * == BEGIN LICENSE ==
 6  
  * 
 7  
  * Licensed under the terms of any of the following licenses at your
 8  
  * choice:
 9  
  * 
 10  
  *  - GNU General Public License Version 2 or later (the "GPL")
 11  
  *    http://www.gnu.org/licenses/gpl.html
 12  
  * 
 13  
  *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 14  
  *    http://www.gnu.org/licenses/lgpl.html
 15  
  * 
 16  
  *  - Mozilla Public License Version 1.1 or later (the "MPL")
 17  
  *    http://www.mozilla.org/MPL/MPL-1.1.html
 18  
  * 
 19  
  * == END LICENSE ==
 20  
  */
 21  
 package net.fckeditor.localization;
 22  
 
 23  
 import java.io.BufferedInputStream;
 24  
 import java.io.InputStream;
 25  
 import java.text.MessageFormat;
 26  
 import java.util.Collections;
 27  
 import java.util.Enumeration;
 28  
 import java.util.HashMap;
 29  
 import java.util.Locale;
 30  
 import java.util.Map;
 31  
 import java.util.Properties;
 32  
 import java.util.ResourceBundle;
 33  
 
 34  
 import javax.servlet.http.HttpServletRequest;
 35  
 
 36  
 import net.fckeditor.handlers.PropertiesLoader;
 37  
 import net.fckeditor.tool.Utils;
 38  
 
 39  
 import org.slf4j.Logger;
 40  
 import org.slf4j.LoggerFactory;
 41  
 
 42  
 /**
 43  
  * Provides access to localized messages (properties).
 44  
  * <p>
 45  
  * Localized messages are loaded for a particular locale from a HTTP request.
 46  
  * The locale is resolved by the current {@link LocaleResolver}
 47  
  * instance/singleton. If a locale or a bundle for a locale cannot be found,
 48  
  * default messages are used.
 49  
  * </p>
 50  
  * <p>
 51  
  * Note: Loaded messages are cached per locale, any subsequent call of the same
 52  
  * locale will be served by the cache instead of another resource bundle
 53  
  * retrieval.
 54  
  * </p>
 55  
  * 
 56  
  * @version $Id: LocalizedMessages.java 4785 2009-12-21 20:10:28Z mosipov $
 57  
  */
 58  
 public class LocalizedMessages {
 59  
 
 60  0
         private static final Map<Locale, LocalizedMessages> prototypes = Collections
 61  
                         .synchronizedMap(new HashMap<Locale, LocalizedMessages>());
 62  
         private static final String DEFAULT_FILENAME = "default_messages.properties"; //$NON-NLS-1$
 63  
         private static final String LOCAL_PROPERTIES = "fckeditor_messages"; //$NON-NLS-1$
 64  0
         private static final Properties defaultProperties = new Properties();
 65  
         
 66  
         private Properties properties;
 67  
         private static LocaleResolver localeResolver;
 68  0
         private static final Locale NEUTRAL = new Locale(Utils.EMPTY_STRING); //$NON-NLS-1$
 69  0
         private static final Logger logger = LoggerFactory
 70  0
                         .getLogger(LocalizedMessages.class);
 71  
 
 72  
         static {
 73  
 
 74  0
                 InputStream in = LocalizedMessages.class
 75  
                                 .getResourceAsStream(DEFAULT_FILENAME);
 76  
 
 77  0
                 if (in == null) {
 78  0
                         logger.error("{} not found", DEFAULT_FILENAME); //$NON-NLS-1$
 79  0
                         throw new RuntimeException(DEFAULT_FILENAME + " not found"); //$NON-NLS-1$
 80  
                 } else {
 81  0
                         if (!(in instanceof BufferedInputStream))
 82  0
                                 in = new BufferedInputStream(in);
 83  
 
 84  
                         try {
 85  0
                                 defaultProperties.load(in);
 86  0
                                 in.close();
 87  0
                                 logger.debug("{} loaded", DEFAULT_FILENAME); //$NON-NLS-1$
 88  0
                         } catch (Exception e) {
 89  0
                                 logger.error("Error while loading {}", DEFAULT_FILENAME); //$NON-NLS-1$
 90  0
                                 throw new RuntimeException(
 91  
                                                 "Error while loading " + DEFAULT_FILENAME, e); //$NON-NLS-1$
 92  0
                         }
 93  
                 }
 94  0
         }
 95  
 
 96  
         /**
 97  
          * Returns an instance of <code>LocalizedMessages</code> for a given
 98  
          * request. This method automatically determines the locale of this request
 99  
          * and loads the appropriate bundle. If locale is null or not available,
 100  
          * the default locale will be used.
 101  
          * 
 102  
          * @param request
 103  
          *            the current request instance
 104  
          * @return instance with localized messages
 105  
          */
 106  
         public static LocalizedMessages getInstance(HttpServletRequest request) {
 107  
 
 108  0
                 if (request == null)
 109  0
                         throw new NullPointerException("the request cannot be null");
 110  
                 
 111  0
                 Locale locale = getLocaleResolverInstance().resolveLocale(request);
 112  
                 
 113  0
                 if (locale == null)
 114  0
                         locale = NEUTRAL;
 115  
                 
 116  0
                 synchronized (LocalizedMessages.class) {
 117  0
                         if (!prototypes.containsKey(locale))
 118  0
                                 prototypes.put(locale, new LocalizedMessages(locale));
 119  0
                 }
 120  
                 
 121  
                 // for now we don't need any cloning since the values are accessed
 122  
                 // read-only
 123  0
                 return prototypes.get(locale);
 124  
 
 125  
         }
 126  
 
 127  
         /**
 128  
          * Returns the locale resolver instance. The implementation class name is
 129  
          * provided by {@link PropertiesLoader#getLocaleResolverImpl()}.
 130  
          * 
 131  
          * @return the locale resolver instance
 132  
          */
 133  
         private synchronized static LocaleResolver getLocaleResolverInstance() {
 134  
 
 135  0
                 if (localeResolver == null) {
 136  0
                         String className = PropertiesLoader.getLocaleResolverImpl();
 137  
 
 138  0
                         if (Utils.isEmpty(className))
 139  0
                                 logger.error("Empty LocaleResolver implementation class name provided"); //$NON-NLS-1$
 140  
                         else
 141  
                                 try {
 142  0
                                         Class<?> clazz = Class.forName(className);
 143  0
                                         localeResolver = (LocaleResolver) clazz.newInstance();
 144  0
                                         logger.info("LocaleResolver initialized to {}", className); //$NON-NLS-1$
 145  0
                                 } catch (Throwable e) {
 146  0
                                         logger.error("LocaleResolver implementation {} could not be instantiated", className); //$NON-NLS-1$
 147  0
                                         throw new RuntimeException("LocaleResolver implementation " + className + " could not be instantiated", e); //$NON-NLS-1$
 148  0
                                 }
 149  
                 }
 150  
 
 151  0
                 return localeResolver;
 152  
         }
 153  
 
 154  
         /**
 155  
          * Loads the localized messages for the given locale. This constructor loads
 156  
          * the resource bundle for this locale and only for this, in other words it
 157  
          * short-circuits the default resource bundle load mechanism in order to
 158  
          * prevent the loading of the system default locale which may result in a
 159  
          * completely different resource bundle.
 160  
          * 
 161  
          * @param locale
 162  
          *            the locale of the new localized messages
 163  
          */
 164  0
         private LocalizedMessages(Locale locale) {
 165  
 
 166  0
                 properties = new Properties(defaultProperties);
 167  
 
 168  0
                 ResourceBundle localized = null;
 169  
                 try {
 170  0
                         localized = ResourceBundle.getBundle(LOCAL_PROPERTIES, locale,
 171  
                                         Thread.currentThread().getContextClassLoader());
 172  0
                 } catch (Exception e) {
 173  
                         ; // do nothing
 174  0
                 }
 175  
 
 176  0
                 if (localized != null
 177  
                                 && localized.getLocale().getLanguage().equals(
 178  
                                                 locale.getLanguage())) {
 179  0
                         Enumeration<String> keys = localized.getKeys();
 180  
 
 181  0
                         while (keys.hasMoreElements()) {
 182  0
                                 String key = keys.nextElement();
 183  0
                                 properties.setProperty(key, localized.getString(key));
 184  0
                         }
 185  
 
 186  0
                         logger.debug("Resource bundle for locale '{}' loaded", locale); //$NON-NLS-1$
 187  0
                 } else {
 188  0
                         logger.debug("No resource bundle for locale '{}' found, loading default bundle", locale); //$NON-NLS-1$
 189  
 
 190  0
                         ResourceBundle base = null;
 191  
                         try {
 192  0
                                 base = ResourceBundle.getBundle(LOCAL_PROPERTIES, NEUTRAL,
 193  
                                                 Thread.currentThread().getContextClassLoader());
 194  0
                         } catch (Exception e) {
 195  
                                 ; // do nothing
 196  0
                         }
 197  
 
 198  0
                         if (base != null && base.getLocale().equals(NEUTRAL)) {
 199  0
                                 Enumeration<String> keys = base.getKeys();
 200  
 
 201  0
                                 while (keys.hasMoreElements()) {
 202  0
                                         String key = keys.nextElement();
 203  0
                                         properties.setProperty(key, base.getString(key));
 204  0
                                 }
 205  
                         }
 206  
 
 207  
                 }
 208  
 
 209  0
         }
 210  
 
 211  
         /**
 212  
          * Searches for the message with the specified key in this message list.
 213  
          * 
 214  
          * @see Properties#getProperty(String)
 215  
          */
 216  
         private String getMessage(String key) {
 217  0
                 return properties.getProperty(key);
 218  
         }
 219  
 
 220  
         /** Returns localized <code>editor.compatibleBrowser.yes</code> property. */
 221  
         public String getCompatibleBrowserYes() {
 222  0
                 return getMessage("editor.compatibleBrowser.yes"); //$NON-NLS-1$
 223  
         }
 224  
 
 225  
         /** Returns localized <code>editor.compatibleBrowser.no</code> property. */
 226  
         public String getCompatibleBrowserNo() {
 227  0
                 return getMessage("editor.compatibleBrowser.no"); //$NON-NLS-1$
 228  
         }
 229  
 
 230  
         /** Returns localized <code>connector.fileUpload.enabled</code> property. */
 231  
         public String getFileUploadEnabled() {
 232  0
                 return getMessage("connector.fileUpload.enabled"); //$NON-NLS-1$
 233  
         }
 234  
 
 235  
         /** Returns localized <code>connector.fileUpload.disabled</code> property. */
 236  
         public String getFileUploadDisabled() {
 237  0
                 return getMessage("connector.fileUpload.disabled"); //$NON-NLS-1$
 238  
         }
 239  
 
 240  
         /**
 241  
          * Returns localized <code>connector.file_renamed_warning</code> property.
 242  
          * 
 243  
          * @param newFileName
 244  
          *            the new filename of the warning
 245  
          * @return localized message with new filename
 246  
          */
 247  
         public String getFileRenamedWarning(String newFileName) {
 248  0
                 return MessageFormat.format(getMessage("connector.fileUpload.file_renamed_warning"), newFileName); //$NON-NLS-1$
 249  
         }
 250  
 
 251  
         /** Returns localized <code>connector.fileUpload.invalid_file_type_specified</code> property. */
 252  
         public String getInvalidFileTypeSpecified() {
 253  0
                 return getMessage("connector.fileUpload.invalid_file_type_specified"); //$NON-NLS-1$
 254  
         }
 255  
 
 256  
         /** Returns localized <code>connector.fileUpload.write_error</code> property. */
 257  
         public String getFileUploadWriteError() {
 258  0
                 return getMessage("connector.fileUpload.write_error"); //$NON-NLS-1$
 259  
         }
 260  
 
 261  
         /** Returns localized <code>connector.getResources.enabled</code> property. */
 262  
         public String getGetResourcesEnabled() {
 263  0
                 return getMessage("connector.getResources.enabled"); //$NON-NLS-1$
 264  
         }
 265  
 
 266  
         /** Returns localized <code>connector.getResources.disabled</code> property. */
 267  
         public String getGetResourcesDisabled() {
 268  0
                 return getMessage("connector.getResources.disabled"); //$NON-NLS-1$
 269  
         }
 270  
 
 271  
         /** Returns localized <code>connector.getResources.read_error</code> property. */
 272  
         public String getGetResourcesReadError() {
 273  0
                 return getMessage("connector.getResources.read_error"); //$NON-NLS-1$
 274  
         }
 275  
 
 276  
         /** Returns localized <code>connector.createFolder.enabled</code> property. */
 277  
         public String getCreateFolderEnabled() {
 278  0
                 return getMessage("connector.createFolder.enabled"); //$NON-NLS-1$
 279  
         }
 280  
 
 281  
         /** Returns localized <code>connector.createFolder.disabled</code> property. */
 282  
         public String getCreateFolderDisabled() {
 283  0
                 return getMessage("connector.createFolder.disabled"); //$NON-NLS-1$
 284  
         }
 285  
 
 286  
         /** Returns localized <code>connector.invalid_command_specified</code> property. */
 287  
         public String getInvalidCommandSpecified() {
 288  0
                 return getMessage("connector.invalid_command_specified"); //$NON-NLS-1$
 289  
         }
 290  
 
 291  
         /** Returns localized <code>connector.createFolder.folder_already_exists_error</code> property. */
 292  
         public String getFolderAlreadyExistsError() {
 293  0
                 return getMessage("connector.createFolder.folder_already_exists_error"); //$NON-NLS-1$
 294  
         }
 295  
 
 296  
         /** Returns localized <code>connector.createFolder.invalid_new_folder_name_specified</code> property. */
 297  
         public String getInvalidNewFolderNameSpecified() {
 298  0
                 return getMessage("connector.createFolder.invalid_new_folder_name_specified"); //$NON-NLS-1$
 299  
         }
 300  
 
 301  
         /** Returns localized <code>connector.createFolder.write_error</code> property. */
 302  
         public String getCreateFolderWriteError() {
 303  0
                 return getMessage("connector.createFolder.write_error"); //$NON-NLS-1$
 304  
         }
 305  
 
 306  
         /** Returns localized <code>connector.invalid_resource_type_specified</code> property. */
 307  
         public String getInvalidResouceTypeSpecified() {
 308  0
                 return getMessage("connector.invalid_resource_type_specified"); //$NON-NLS-1$
 309  
         }
 310  
 
 311  
         /** Returns localized <code>connector.invalid_current_folder_specified</code> property. */
 312  
         public String getInvalidCurrentFolderSpecified() {
 313  0
                 return getMessage("connector.invalid_current_folder_specified"); //$NON-NLS-1$
 314  
         }
 315  
 
 316  
 }