1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.util;
  28 
  29 import com.sun.javatest.ResourceLoader;
  30 
  31 import java.security.AccessController;
  32 import java.security.PrivilegedAction;
  33 import java.text.MessageFormat;
  34 import java.util.Enumeration;
  35 import java.util.Locale;
  36 import java.util.ResourceBundle;
  37 import java.util.MissingResourceException;
  38 
  39 /**
  40  * A class that lazily opens a package-specific resource bundle
  41  * containing localization data for a class.
  42  */
  43 public class I18NResourceBundle extends ResourceBundle
  44 {
  45     /**
  46      * Get a package-specific resource bundle for a class containing localization data.
  47      * The bundle is named i18n.properties in the same
  48      * package as the given class.
  49      * @param c the class for which to obtain the resource bundle
  50      * @return the appropriate resource bundle for the class
  51      */
  52     public static I18NResourceBundle getBundleForClass(Class<?> c) {
  53         String cn = c.getName();
  54         int dot = cn.lastIndexOf('.');
  55         String rn = (dot == -1 ? "i18n" : cn.substring(0, dot) + ".i18n");
  56         boolean logging = (logClassPrefix == null ? false : cn.startsWith(logClassPrefix));
  57         return new I18NResourceBundle(rn, logging, c.getClassLoader());
  58     }
  59 
  60     /**
  61      * Get an entry from the resource bundle.
  62      * If the resource cannot be found, a message is printed to the console
  63      * and the result will be a string containing the method parameters.
  64      * @param key the name of the entry to be returned
  65      * @param arg an argument to be formatted into the result using
  66      * {@link java.text.MessageFormat#format}
  67      * @return the formatted string
  68      */
  69     public String getString(String key, Object arg) {
  70         return getString(key, new Object[] {arg});
  71     }
  72 
  73     /**
  74      * Get an entry from the resource bundle.
  75      * If the resource cannot be found, a message is printed to the console
  76      * and the result will be a string containing the method parameters.
  77      * @param key the name of the entry to be returned
  78      * @param args an array of arguments to be formatted into the result using
  79      * {@link java.text.MessageFormat#format}
  80      * @return the formatted string
  81      */
  82     public String getString(String key, Object[] args) {
  83         try {
  84             return MessageFormat.format(getString(key), args);
  85         }
  86         catch (MissingResourceException e) {
  87             System.err.println("WARNING: missing resource: " + key + " for " + name);
  88             StringBuffer sb = new StringBuffer(key);
  89             for (int i = 0; i < args.length; i++) {
  90                 sb.append('\n');
  91                 sb.append(args[i].toString());
  92             }
  93             return sb.toString();
  94         }
  95     }
  96 
  97     /**
  98      * Get an entry from the bundle, returning null if it is not found.
  99      * @param key the name of the entry to be returned
 100      * @return the value of the entry, or null if it is not found.
 101      */
 102     public String getOptionalString(String key) {
 103         try {
 104             String s = (String) getObj(key);
 105             if (s != null && logging) {
 106                 System.out.println("i18n: " + key);
 107             }
 108             return s;
 109         }
 110         catch (MissingResourceException e) {
 111             return null;
 112         }
 113     }
 114 
 115     private Object getObj(String key) throws MissingResourceException {
 116         try {
 117             if (delegate == null) {
 118                 delegate = AccessController.doPrivileged(
 119                         new PrivilegedAction<ResourceBundle>() {
 120                             public ResourceBundle run() {
 121                                 return ResourceLoader.getBundle(name, Locale.getDefault(), classLoader);
 122                             }
 123                         });
 124             }
 125             return delegate.getObject(key);
 126         } catch (MissingResourceException e) {
 127             ResourceBundle bundle = AccessController.doPrivileged(
 128                     new PrivilegedAction<ResourceBundle>() {
 129                         public ResourceBundle run() {
 130                             return ResourceBundle.getBundle(name, Locale.getDefault(), classLoader);
 131                         }
 132                     });
 133             return bundle.getObject(key);
 134         }
 135     }
 136 
 137     /**
 138      * Create a resource bundle for the given name.
 139      * The actual resource bundle will not be loaded until it is needed.
 140      * @param name The name of the actual resource bundle to use.
 141      */
 142     private I18NResourceBundle(String name, boolean logging, ClassLoader cl) {
 143         this.name = name;
 144         this.logging = logging;
 145         this.classLoader = cl;
 146     }
 147 
 148     /**
 149      * A required internal method for ResourceBundle.
 150      * Load the actual resource bundle, if it has not yet been loaded,
 151      * then hand the request off to that bundle.
 152      * If the resource cannot be found, a message is printed to the console
 153      * and the result will be the original key.
 154      */
 155     protected Object handleGetObject(String key) throws MissingResourceException {
 156         try {
 157             if (logging) {
 158                 System.out.println("i18n: " + key);
 159             }
 160             return getObj(key);
 161         }
 162         catch (MissingResourceException e) {
 163             System.err.println("WARNING: missing resource: " + key + " for " + name);
 164             return key;
 165         }
 166     }
 167 
 168     /**
 169      * A required internal method for ResourceBundle.
 170      * Load the actual resource bundle, if it has not yet been loaded,
 171      * then hand the request off to that bundle.
 172      */
 173     public Enumeration<String> getKeys() {
 174         if (delegate == null) {
 175             delegate = AccessController.doPrivileged(
 176                     new PrivilegedAction<ResourceBundle>() {
 177                         public ResourceBundle run() {
 178                             return ResourceLoader.getBundle(name, Locale.getDefault(), classLoader);
 179                         }
 180                     });
 181 
 182         }
 183         if (delegate.getKeys().hasMoreElements()) {
 184             return delegate.getKeys();
 185         }
 186 
 187         ResourceBundle bundle = AccessController.doPrivileged(
 188                 new PrivilegedAction<ResourceBundle>() {
 189                     public ResourceBundle run() {
 190                         return ResourceBundle.getBundle(name, Locale.getDefault(), classLoader);
 191                     }
 192                 });
 193         return bundle.getKeys();
 194     }
 195 
 196     /**
 197      * Returns the name of this bundle (useful for methods using
 198      * bundle name instead of instance, such as <code>Logger</code> creation,
 199      * @return the name of this resource bundle
 200      */
 201 
 202     public String getName() {
 203         return name;
 204     }
 205 
 206     private String name;
 207     private ResourceBundle delegate;
 208     private boolean logging;
 209     private ClassLoader classLoader;
 210     private static final String logClassPrefix = System.getProperty("javatest.i18n.log");
 211 }