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    }