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