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