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
19 package org.apache.catalina.util;
20
21 import java.text.MessageFormat;
22 import java.util.Hashtable;
23 import java.util.Locale;
24 import java.util.MissingResourceException;
25 import java.util.ResourceBundle;
26 import java.net.URLClassLoader;
27
28 /**
29 * An internationalization / localization helper class which reduces
30 * the bother of handling ResourceBundles and takes care of the
31 * common cases of message formating which otherwise require the
32 * creation of Object arrays and such.
33 *
34 * <p>The StringManager operates on a package basis. One StringManager
35 * per package can be created and accessed via the getManager method
36 * call.
37 *
38 * <p>The StringManager will look for a ResourceBundle named by
39 * the package name given plus the suffix of "LocalStrings". In
40 * practice, this means that the localized information will be contained
41 * in a LocalStrings.properties file located in the package
42 * directory of the classpath.
43 *
44 * <p>Please see the documentation for java.util.ResourceBundle for
45 * more information.
46 *
47 * @author James Duncan Davidson [duncan@eng.sun.com]
48 * @author James Todd [gonzo@eng.sun.com]
49 */
50
51 public class StringManager {
52
53 /**
54 * The ResourceBundle for this StringManager.
55 */
56
57 private ResourceBundle bundle;
58
59 private static org.apache.juli.logging.Log log=
60 org.apache.juli.logging.LogFactory.getLog( StringManager.class );
61
62 /**
63 * Creates a new StringManager for a given package. This is a
64 * private method and all access to it is arbitrated by the
65 * static getManager method call so that only one StringManager
66 * per package will be created.
67 *
68 * @param packageName Name of package to create StringManager for.
69 */
70
71 private StringManager(String packageName) {
72 String bundleName = packageName + ".LocalStrings";
73 try {
74 bundle = ResourceBundle.getBundle(bundleName);
75 return;
76 } catch( MissingResourceException ex ) {
77 // Try from the current loader ( that's the case for trusted apps )
78 ClassLoader cl=Thread.currentThread().getContextClassLoader();
79 if( cl != null ) {
80 try {
81 bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl);
82 return;
83 } catch(MissingResourceException ex2) {
84 }
85 }
86 if( cl==null )
87 cl=this.getClass().getClassLoader();
88
89 if (log.isDebugEnabled())
90 log.debug("Can't find resource " + bundleName +
91 " " + cl);
92 if( cl instanceof URLClassLoader ) {
93 if (log.isDebugEnabled())
94 log.debug( ((URLClassLoader)cl).getURLs());
95 }
96 }
97 }
98
99 /**
100 * Get a string from the underlying resource bundle.
101 *
102 * @param key The resource name
103 */
104 public String getString(String key) {
105 return MessageFormat.format(getStringInternal(key), (Object [])null);
106 }
107
108
109 protected String getStringInternal(String key) {
110 if (key == null) {
111 String msg = "key is null";
112
113 throw new NullPointerException(msg);
114 }
115
116 String str = null;
117
118 if( bundle==null )
119 return key;
120 try {
121 str = bundle.getString(key);
122 } catch (MissingResourceException mre) {
123 str = "Cannot find message associated with key '" + key + "'";
124 }
125
126 return str;
127 }
128
129 /**
130 * Get a string from the underlying resource bundle and format
131 * it with the given set of arguments.
132 *
133 * @param key The resource name
134 * @param args Formatting directives
135 */
136
137 public String getString(String key, Object[] args) {
138 String iString = null;
139 String value = getStringInternal(key);
140
141 // this check for the runtime exception is some pre 1.1.6
142 // VM's don't do an automatic toString() on the passed in
143 // objects and barf out
144
145 try {
146 // ensure the arguments are not null so pre 1.2 VM's don't barf
147 Object nonNullArgs[] = args;
148 for (int i=0; i<args.length; i++) {
149 if (args[i] == null) {
150 if (nonNullArgs==args) nonNullArgs=(Object[])args.clone();
151 nonNullArgs[i] = "null";
152 }
153 }
154
155 iString = MessageFormat.format(value, nonNullArgs);
156 } catch (IllegalArgumentException iae) {
157 StringBuffer buf = new StringBuffer();
158 buf.append(value);
159 for (int i = 0; i < args.length; i++) {
160 buf.append(" arg[" + i + "]=" + args[i]);
161 }
162 iString = buf.toString();
163 }
164 return iString;
165 }
166
167 /**
168 * Get a string from the underlying resource bundle and format it
169 * with the given object argument. This argument can of course be
170 * a String object.
171 *
172 * @param key The resource name
173 * @param arg Formatting directive
174 */
175
176 public String getString(String key, Object arg) {
177 Object[] args = new Object[] {arg};
178 return getString(key, args);
179 }
180
181 /**
182 * Get a string from the underlying resource bundle and format it
183 * with the given object arguments. These arguments can of course
184 * be String objects.
185 *
186 * @param key The resource name
187 * @param arg1 Formatting directive
188 * @param arg2 Formatting directive
189 */
190
191 public String getString(String key, Object arg1, Object arg2) {
192 Object[] args = new Object[] {arg1, arg2};
193 return getString(key, args);
194 }
195
196 /**
197 * Get a string from the underlying resource bundle and format it
198 * with the given object arguments. These arguments can of course
199 * be String objects.
200 *
201 * @param key The resource name
202 * @param arg1 Formatting directive
203 * @param arg2 Formatting directive
204 * @param arg3 Formatting directive
205 */
206
207 public String getString(String key, Object arg1, Object arg2,
208 Object arg3) {
209 Object[] args = new Object[] {arg1, arg2, arg3};
210 return getString(key, args);
211 }
212
213 /**
214 * Get a string from the underlying resource bundle and format it
215 * with the given object arguments. These arguments can of course
216 * be String objects.
217 *
218 * @param key The resource name
219 * @param arg1 Formatting directive
220 * @param arg2 Formatting directive
221 * @param arg3 Formatting directive
222 * @param arg4 Formatting directive
223 */
224
225 public String getString(String key, Object arg1, Object arg2,
226 Object arg3, Object arg4) {
227 Object[] args = new Object[] {arg1, arg2, arg3, arg4};
228 return getString(key, args);
229 }
230 // --------------------------------------------------------------
231 // STATIC SUPPORT METHODS
232 // --------------------------------------------------------------
233
234 private static Hashtable managers = new Hashtable();
235
236 /**
237 * Get the StringManager for a particular package. If a manager for
238 * a package already exists, it will be reused, else a new
239 * StringManager will be created and returned.
240 *
241 * @param packageName The package name
242 */
243
244 public synchronized static StringManager getManager(String packageName) {
245 StringManager mgr = (StringManager)managers.get(packageName);
246
247 if (mgr == null) {
248 mgr = new StringManager(packageName);
249 managers.put(packageName, mgr);
250 }
251 return mgr;
252 }
253 }