001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.resources.impl;
019
020 import java.util.Collections;
021 import java.util.Iterator;
022 import java.util.Locale;
023 import java.util.MissingResourceException;
024 import java.util.ResourceBundle;
025
026 import org.apache.commons.logging.Log;
027 import org.apache.commons.logging.LogFactory;
028 import org.apache.commons.resources.ResourcesException;
029 import org.apache.commons.resources.ResourcesKeyException;
030 import org.apache.commons.resources.util.IteratorEnumeration;
031
032 /**
033 * <p>Concrete implementation of
034 * {@link org.apache.commons.resources.Resources} that wraps a set
035 * (one per Locale) of <code>java.util.ResourceBundle</code> instances
036 * that share a common base name.</p>
037 */
038 public class ResourceBundleResources extends ResourcesBase {
039
040 /**
041 * <p>The logging instance for this class.</p>
042 */
043 private transient Log log =
044 LogFactory.getLog(ResourceBundleResources.class);
045
046 // ----------------------------------------------------------- Constructors
047
048
049 /**
050 * <p>Create a new {@link org.apache.commons.resources.Resources}
051 * instance with the specified
052 * logical name and bundle base name.</p>
053 *
054 * @param name Logical name of the new instance
055 * @param base Fully qualified base name of the <code>ResourceBundle</code>
056 * instances to be wrapped
057 */
058 public ResourceBundleResources(String name, String base) {
059
060 super(name);
061 this.base = base;
062
063 }
064
065
066 // ----------------------------------------------------- Instance Variables
067
068
069 /**
070 * <p>The fully qualified base name of the <code>ResourceBundle</code>
071 * instances to be wrapped.</p>
072 */
073 private String base = null;
074
075
076 // ------------------------------------------------------------- Properties
077
078
079 /**
080 * <p>Return the fully qualified base name of the
081 * <code>ResourceBundle</code> instances we are wrapping.</p>
082 * @return The base name of this resources instance.
083 */
084 public String getBase() {
085
086 return (this.base);
087
088 }
089
090 /**
091 * <p>Return an <code>Iterator</code> over the defined keys in this
092 * {@link org.apache.commons.resources.Resources} instance.</p>
093 *
094 * @return The keys contained in this resources instance.
095 */
096 public Iterator getKeys() {
097
098 try {
099 ResourceBundle bundle = getBundle(null);
100 return new IteratorEnumeration(bundle.getKeys());
101
102 } catch (MissingResourceException e) {
103 return Collections.EMPTY_LIST.iterator();
104 }
105
106 }
107
108
109 // ---------------------------------------------- Content Retrieval Methods
110
111
112 /**
113 * <p>Return the content for the specified <code>key</code> as an
114 * Object, localized based on the specified <code>locale</code>.
115 * </p>
116 *
117 * @param key Identifier for the requested content
118 * @param locale Locale with which to localize retrieval,
119 * or <code>null</code> for the default Locale
120 * @return content for a specified key.
121 *
122 * @exception ResourcesException if an error occurs retrieving or
123 * returning the requested content
124 * @exception ResourcesKeyException if the no value for the specified
125 * key was found, and <code>isReturnNull()</code> returns
126 * <code>false</code>
127 */
128 public Object getObject(String key, Locale locale) {
129
130 if (getLog().isTraceEnabled()) {
131 getLog().trace("Retrieving message for key '" + key + "' and locale '"
132 + locale + "'");
133 }
134
135 try {
136 ResourceBundle bundle = getBundle(locale);
137 Object object = bundle.getObject(key);
138 if (getLog().isTraceEnabled()) {
139 getLog().trace("Retrieved object for key '" + key +
140 "' and locale '" + locale +
141 "' is '" + object + "'");
142 }
143 return object;
144
145 } catch (MissingResourceException e) {
146 if (getLog().isTraceEnabled()) {
147 getLog().trace("No resource found for key '" + key +
148 "' and locale '" + locale + "'");
149 }
150 if (isReturnNull()) {
151 return (null);
152 } else {
153 throw new ResourcesKeyException(key);
154 }
155 }
156
157 }
158
159
160 // ------------------------------------------------------ Protected Methods
161
162
163 /**
164 * <p>Return the appropriate <code>ResourceBundle</code> instance
165 * that corresponds to the specified <code>locale</code> parameter.
166 * The first time a particular bundle is requested, cache it so
167 * that subsequent requests will operate more quickly.</p>
168 *
169 * @param locale Locale with which to localize retrieval,
170 * or <code>null</code> for the default Locale
171 * @return The Resource Bundle corresponding to the locale and time zone.
172 *
173 * @exception MissingResourceException if the requested Resourcebundle
174 * cannot be acquired
175 */
176 protected ResourceBundle getBundle(Locale locale)
177 throws MissingResourceException {
178
179 if (locale == null) {
180 locale = Locale.getDefault();
181 }
182
183 // Locate the appropriate ClassLoader
184 ClassLoader loader = getClassLoader();
185
186 // Locate the requested ResourceBundle instance
187 ResourceBundle bundle = ResourceBundle.getBundle(base, locale, loader);
188
189 return (bundle);
190
191 }
192
193
194 /**
195 * <p>Return the <code>ClassLoader</code> for which we are mapping
196 * <code>ResourceBundle</code> instances.</p>
197 * @return The Class Loader for the resource bundle.
198 */
199 protected ClassLoader getClassLoader() {
200
201 ClassLoader loader = Thread.currentThread().getContextClassLoader();
202
203 if (loader == null) {
204 loader = this.getClass().getClassLoader();
205 }
206
207 return (loader);
208
209 }
210
211 /**
212 * Accessor method for Log instance.
213 *
214 * The Log instance variable is transient and
215 * accessing it through this method ensures it
216 * is re-initialized when this instance is
217 * de-serialized.
218 *
219 * @return The Log instance.
220 */
221 private Log getLog() {
222 if (log == null) {
223 log = LogFactory.getLog(ResourceBundleResources.class);
224 }
225 return log;
226 }
227
228 }