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 }