1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */

17
18 package org.apache.naming;
19
20 import java.text.MessageFormat;
21 import java.util.Hashtable;
22 import java.util.Locale;
23 import java.util.MissingResourceException;
24 import java.util.ResourceBundle;
25
26 /**
27  * An internationalization / localization helper class which reduces
28  * the bother of handling ResourceBundles and takes care of the
29  * common cases of message formating which otherwise require the
30  * creation of Object arrays and such.
31  *
32  * <p>The StringManager operates on a package basis. One StringManager
33  * per package can be created and accessed via the getManager method
34  * call.
35  *
36  * <p>The StringManager will look for a ResourceBundle named by
37  * the package name given plus the suffix of "LocalStrings". In
38  * practice, this means that the localized information will be contained
39  * in a LocalStrings.properties file located in the package
40  * directory of the classpath.
41  *
42  * <p>Please see the documentation for java.util.ResourceBundle for
43  * more information.
44  *
45  * @author James Duncan Davidson [duncan@eng.sun.com]
46  * @author James Todd [gonzo@eng.sun.com]
47  * @author Mel Martinez [mmartinez@g1440.com]
48  * @see java.util.ResourceBundle
49  */

50 public class StringManager {
51
52     /**
53      * The ResourceBundle for this StringManager.
54      */

55     private final ResourceBundle bundle;
56     private final Locale locale;
57
58     /**
59      * Creates a new StringManager for a given package. This is a
60      * private method and all access to it is arbitrated by the
61      * static getManager method call so that only one StringManager
62      * per package will be created.
63      *
64      * @param packageName Name of package to create StringManager for.
65      */

66     private StringManager(String packageName) {
67         String bundleName = packageName + ".LocalStrings";
68         ResourceBundle tempBundle = null;
69         try {
70             tempBundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
71         } catch( MissingResourceException ex ) {
72             // Try from the current loader (that's the case for trusted apps)
73             // Should only be required if using a TC5 style classloader structure
74             // where common != shared != server
75             ClassLoader cl = Thread.currentThread().getContextClassLoader();
76             if( cl != null ) {
77                 try {
78                     tempBundle = ResourceBundle.getBundle(
79                             bundleName, Locale.getDefault(), cl);
80                 } catch(MissingResourceException ex2) {
81                     // Ignore
82                 }
83             }
84         }
85         // Get the actual locale, which may be different from the requested one
86         if (tempBundle != null) {
87             locale = tempBundle.getLocale();
88         } else {
89             locale = null;
90         }
91         bundle = tempBundle;
92     }
93
94     /**
95         Get a string from the underlying resource bundle or return
96         null if the String is not found.
97
98         @param key to desired resource String
99         @return resource String matching <i>key</i> from underlying
100                 bundle or null if not found.
101         @throws IllegalArgumentException if <i>key</i> is null.
102      */

103     public String getString(String key) {
104         if(key == null){
105             String msg = "key may not have a null value";
106
107             throw new IllegalArgumentException(msg);
108         }
109
110         String str = null;
111
112         try {
113             // Avoid NPE if bundle is null and treat it like an MRE
114             if (bundle != null) {
115                 str = bundle.getString(key);
116             }
117         } catch(MissingResourceException mre) {
118             //bad: shouldn't mask an exception the following way:
119             //   str = "[cannot find message associated with key '" + key + "' due to " + mre + "]";
120             //     because it hides the fact that the String was missing
121             //     from the calling code.
122             //good: could just throw the exception (or wrap it in another)
123             //      but that would probably cause much havoc on existing
124             //      code.
125             //better: consistent with container pattern to
126             //      simply return null.  Calling code can then do
127             //      a null check.
128             str = null;
129         }
130
131         return str;
132     }
133
134     /**
135      * Get a string from the underlying resource bundle and format
136      * it with the given set of arguments.
137      *
138      * @param key  The key for the required message
139      * @param args The values to insert into the message
140      *
141      * @return The request string formatted with the provided arguments or the
142      *         key if the key was not found.
143      */

144     public String getString(final String key, final Object... args) {
145         String value = getString(key);
146         if (value == null) {
147             value = key;
148         }
149
150         MessageFormat mf = new MessageFormat(value);
151         mf.setLocale(locale);
152         return mf.format(args, new StringBuffer(), null).toString();
153     }
154
155     // --------------------------------------------------------------
156     // STATIC SUPPORT METHODS
157     // --------------------------------------------------------------
158
159     private static final Hashtable<String, StringManager> managers =
160             new Hashtable<>();
161
162     /**
163      * Get the StringManager for a particular package. If a manager for
164      * a package already exists, it will be reused, else a new
165      * StringManager will be created and returned.
166      *
167      * @param packageName The package name
168      *
169      * @return The instance associated with the given package
170      */

171     public static final synchronized StringManager getManager(String packageName) {
172         StringManager mgr = managers.get(packageName);
173         if (mgr == null) {
174             mgr = new StringManager(packageName);
175             managers.put(packageName, mgr);
176         }
177         return mgr;
178     }
179
180
181     public static final StringManager getManager(Class<?> clazz) {
182         return getManager(clazz.getPackage().getName());
183     }
184 }
185