View Javadoc

1   /*
2    * $Id: PropertyResources.java 348371 2005-11-23 04:56:51Z niallp $
3    * $Revision: 348371 $
4    * $Date: 2005-11-23 04:56:51 +0000 (Wed, 23 Nov 2005) $
5    *
6    * ====================================================================
7    *
8    *  Copyright 2003-2005 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   *
22   */
23  
24  package org.apache.commons.resources.impl;
25  
26  import java.io.FileNotFoundException;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.net.URL;
30  import java.util.Locale;
31  import java.util.Map;
32  import java.util.Properties;
33  
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  
37  /**
38   * <p>Concrete implementation of 
39   * {@link org.apache.commons.resources.Resources} that wraps a family
40   * (one per <code>Locale</code>) of properties files that share a base URL
41   * and have name suffixes reflecting the <code>Locale</code> for which
42   * the document's messages apply.  Resources are looked up in a hierarchy
43   * of properties files in a manner identical to that performed by
44   * <code>java.util.ResourceBundle.getBundle().</code>.</p>
45   *
46   * <p>The base URL passed to our constructor must contain the base name
47   * of the properties file family.
48   * For example, if the configuration URL is passed as
49   * <code>http://localhost/foo/Bar</code>, the resources for the
50   * <code>en_US</code> Locale would be stored under URL
51   * <code>http://localhost/foo/Bar_en_US.properties</code>, and the default
52   * resources would be stored in
53   * <code>http://localhost/foo/Bar.properties</code>.</p>
54   */
55  public class PropertyResources extends CollectionResourcesBase {
56  
57      /**
58       * <p>The <code>Log</code> instance for this class.</p>
59       */
60      private transient Log log = LogFactory.getLog(PropertyResources.class);
61  
62      // ----------------------------------------------------------- Constructors
63  
64      /**
65       * <p>Create a new 
66       * {@link org.apache.commons.resources.Resources} instance with the specified
67       * logical name and base resource URL.</p>
68       *
69       * @param name Logical name of the new instance
70       * @param base Base URL of the family of properties files that contain
71       *  the resource keys and values
72       */
73      public PropertyResources(String name, String base) {
74          super(name, base);
75      }
76  
77  
78      // ------------------------------------------------------ Protected Methods
79  
80  
81      /**
82       * <p>Return a <code>Map</code> containing the name-value mappings for
83       * the specified base URL and requested <code>Locale</code>, if there
84       * are any.  If there are no defined mappings for the specified
85       * <code>Locale</code>, return an empty <code>Map</code> instead.</p>
86       *
87       * <p>Concrete subclasses must override this method to perform the
88       * appropriate lookup.  A typical implementation will construct an
89       * absolute URL based on the specified base URL and <code>Locale</code>,
90       * retrieve the specified resource file (if any), and parse it into
91       * a <code>Map</code> structure.</p>
92       *
93       * <p>Caching of previously retrieved <code>Map</code>s (if any) should
94       * be performed by callers of this method.  Therefore, this method should
95       * always attempt to retrieve the specified resource and load it
96       * appropriately.</p>
97       *
98       * @param baseUrl Base URL of the resource files for this 
99       * {@link org.apache.commons.resources.Resources} instance
100      * @param locale <code>Locale</code> for which name-value mappings
101      *  are requested
102      * @return A name-value Map for the specified URL and locale.
103      */
104     protected Map getLocaleMap(String baseUrl, Locale locale) {
105 
106         if (getLog().isDebugEnabled()) {
107             getLog().debug("Loading locale '" + locale + "' resources from base '" +
108                     baseUrl + "'");
109         }
110 
111         Properties props = new Properties();
112         String name = baseUrl + getLocaleSuffix(locale) + ".properties";
113         InputStream stream = null;
114 
115         try {
116 
117             // Open an input stream to the URL for this locale (if any)
118             if (getLog().isTraceEnabled()) {
119                 getLog().trace("Absolute URL is '" + name + "'");
120             }
121             URL url = new URL(name);
122             stream = url.openStream();
123 
124             // Parse the input stream and populate the name-value mappings map
125             if (getLog().isTraceEnabled()) {
126                 getLog().trace("Parsing input resource");
127             }
128             props.load(stream);
129 
130         } catch (FileNotFoundException e) {
131 
132             // Log and swallow this exception
133             if (getLog().isDebugEnabled()) {
134                 getLog().debug("No resources for locale '" + locale +
135                           "' from base '" + baseUrl + "'");
136             }
137             props.clear();
138 
139         } catch (IOException e) {
140 
141             getLog().warn("IOException loading locale '" + locale +
142                      "' from base '" + baseUrl + "'", e);
143             props.clear();
144 
145         } finally {
146 
147             // Close the input stream that was opened earlier
148             if (stream != null) {
149                 try {
150                     stream.close();
151                 } catch (IOException e) {
152                     getLog().error("Error closing stream.", e);
153                 }
154                 stream = null;
155             }
156 
157         }
158 
159         // Return the populated (or empty) properties
160         return (props);
161 
162     }
163 
164 
165     /**
166      * Accessor method for Log instance.
167      *
168      * The Log instance variable is transient and
169      * accessing it through this method ensures it
170      * is re-initialized when this instance is
171      * de-serialized.
172      *
173      * @return The Log instance.
174      */
175     private Log getLog() {
176         if (log == null) {
177             log =  LogFactory.getLog(PropertyResources.class);
178         }
179         return log;
180     }
181 
182 }