View Javadoc

1   /*
2    * $Id: WebappPropertyResources.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.util.Locale;
30  import java.util.Map;
31  import java.util.Properties;
32  
33  import javax.servlet.ServletContext;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /**
39   * <p>Concrete implementation of {@link org.apache.commons.resources.Resources} that wraps a family
40   * (one per <code>Locale</code> of properties files that share a base
41   * context-relative path for servlet context resources, and have
42   * name suffixes reflecting the <code>Locale</code> for which
43   * the document's messages apply.  Resources are looked up in a hierarchy
44   * of properties files in a manner identical to that performed by
45   * <code>java.util.ResourceBundle.getBundle().</code>.</p>
46   *
47   * <p>The base resource path passed to our constructor must contain the
48   * context-relative base name of the properties file family.
49   * For example, if the base path is passed as
50   * <code>http://localhost/foo/Bar</code>, the resources for the
51   * <code>en_US</code> Locale would be stored under URL
52   * <code>http://localhost/foo/Bar_en_US.properties</code>, and the default
53   * resources would be stored in
54   * <code>http://localhost/foo/Bar.properties</code>.</p>
55   */
56  public class WebappPropertyResources extends CollectionResourcesBase {
57  
58      /**
59       * <p>The <code>Log</code> instance for this class.</p>
60       */
61      private transient Log log =
62          LogFactory.getLog(WebappPropertyResources.class);
63  
64      // ----------------------------------------------------------- Constructors
65  
66  
67      /**
68       * <p>Create a new {@link org.apache.commons.resources.Resources} instance with the specified
69       * logical name and base resource URL.</p>
70       *
71       * @param name Logical name of the new instance
72       * @param base Base URL of the family of properties files that contain
73       *  the resource keys and values
74       * @param servletContext the <code>ServletContext</code> instance
75       *  to use for resolving resource references
76       */
77      public WebappPropertyResources(String name, String base,
78                                     ServletContext servletContext) {
79  
80          super(name, base);
81          this.servletContext = servletContext;
82  
83      }
84  
85  
86      // ----------------------------------------------------- Instance Variables
87  
88  
89      /**
90       * <p>The <code>ServletContext</code> instance for resolving
91       * our resources references.</p>
92       */
93      private ServletContext servletContext = null;
94  
95  
96      // ------------------------------------------------------ Protected Methods
97  
98  
99      /**
100      * <p>Return a <code>Map</code> containing the name-value mappings for
101      * the specified base URL and requested <code>Locale</code>, if there
102      * are any.  If there are no defined mappings for the specified
103      * <code>Locale</code>, return an empty <code>Map</code> instead.</p>
104      *
105      * <p>Concrete subclasses must override this method to perform the
106      * appropriate lookup.  A typical implementation will construct an
107      * absolute URL based on the specified base URL and <code>Locale</code>,
108      * retrieve the specified resource file (if any), and parse it into
109      * a <code>Map</code> structure.</p>
110      *
111      * <p>Caching of previously retrieved <code>Map</code>s (if any) should
112      * be performed by callers of this method.  Therefore, this method should
113      * always attempt to retrieve the specified resource and load it
114      * appropriately.</p>
115      *
116      * @param baseUrl Base URL of the resource files for this {@link org.apache.commons.resources.Resources}
117      *  instance
118      * @param locale <code>Locale</code> for which name-value mappings
119      *  are requested
120      * @return A name-value Map for the specified URL and locale.
121      */
122     protected Map getLocaleMap(String baseUrl, Locale locale) {
123 
124         if (getLog().isDebugEnabled()) {
125             getLog().debug("Loading locale '" + locale + "' resources from base '" +
126                     baseUrl + "'");
127         }
128 
129         Properties props = new Properties();
130         String name = baseUrl.replace('.', '/');
131         name += getLocaleSuffix(locale) + ".properties";
132         
133         InputStream stream = null;
134 
135         try {
136 
137             // Open an input stream to the URL for this locale (if any)
138             if (getLog().isTraceEnabled()) {
139                 getLog().trace("Complete path is '" + name + "'");
140             }
141             try{
142                 stream = servletContext.getResourceAsStream(name);
143             }
144             catch(Exception e){
145                 // not found
146                 // try ContextClassLoader
147             }
148             if (stream == null){
149                 
150                 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
151                 if (classLoader == null) {
152                     classLoader = this.getClass().getClassLoader();
153                 }
154                 stream = classLoader.getResourceAsStream(name);
155             }
156             
157             // Parse the input stream and populate the name-value mappings map
158             if (stream != null) {
159                 if (getLog().isTraceEnabled()) {
160                     getLog().trace("Parsing input resource");
161                 }
162                 props.load(stream);
163             }
164 
165         } catch (FileNotFoundException e) {
166 
167             // Log and swallow this exception
168             if (getLog().isDebugEnabled()) {
169                 getLog().debug("No resources for locale '" + locale +
170                           "' from base '" + baseUrl + "'");
171             }
172             props.clear();
173 
174         } catch (IOException e) {
175 
176             getLog().warn("IOException loading locale '" + locale +
177                      "' from base '" + baseUrl + "'", e);
178             props.clear();
179 
180         } finally {
181 
182             // Close the input stream that was opened earlier
183             if (stream != null) {
184                 try {
185                     stream.close();
186                 } catch (IOException e) {
187                     getLog().error("Error closing stream.", e);
188                 }
189                 stream = null;
190             }
191 
192         }
193 
194         // Return the populated (or empty) properties
195         return (props);
196 
197     }
198 
199     /**
200      * Accessor method for Log instance.
201      *
202      * The Log instance variable is transient and
203      * accessing it through this method ensures it
204      * is re-initialized when this instance is
205      * de-serialized.
206      *
207      * @return The Log instance.
208      */
209     private Log getLog() {
210         if (log == null) {
211             log =  LogFactory.getLog(WebappPropertyResources.class);
212         }
213         return log;
214     }
215 
216 }