Clover coverage report - Code Coverage for tapestry release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:05:49 EDT
file stats: LOC: 347   Methods: 16
NCLOC: 219   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
ComponentMessagesSourceImpl.java 91.7% 97.7% 93.8% 96.1%
coverage coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.tapestry.services.impl;
 16   
 
 17   
 import java.io.BufferedInputStream;
 18   
 import java.io.IOException;
 19   
 import java.io.InputStream;
 20   
 import java.net.URL;
 21   
 import java.util.ArrayList;
 22   
 import java.util.Collections;
 23   
 import java.util.HashMap;
 24   
 import java.util.Iterator;
 25   
 import java.util.List;
 26   
 import java.util.Locale;
 27   
 import java.util.Map;
 28   
 import java.util.Properties;
 29   
 
 30   
 import org.apache.hivemind.ApplicationRuntimeException;
 31   
 import org.apache.hivemind.Messages;
 32   
 import org.apache.hivemind.Resource;
 33   
 import org.apache.hivemind.util.Defense;
 34   
 import org.apache.hivemind.util.LocalizedNameGenerator;
 35   
 import org.apache.tapestry.IComponent;
 36   
 import org.apache.tapestry.INamespace;
 37   
 import org.apache.tapestry.event.ResetEventListener;
 38   
 import org.apache.tapestry.services.ComponentMessagesSource;
 39   
 import org.apache.tapestry.services.ComponentPropertySource;
 40   
 import org.apache.tapestry.util.text.LocalizedProperties;
 41   
 
 42   
 /**
 43   
  * Service used to access localized properties for a component.
 44   
  * 
 45   
  * @author Howard Lewis Ship
 46   
  * @since 2.0.4
 47   
  */
 48   
 
 49   
 public class ComponentMessagesSourceImpl implements ComponentMessagesSource, ResetEventListener
 50   
 {
 51   
     private Properties _emptyProperties = new Properties();
 52   
 
 53   
     private static final String SUFFIX = ".properties";
 54   
 
 55   
     /**
 56   
      * The name of the component/application/etc property that will be used to determine the
 57   
      * encoding to use when loading the messages
 58   
      */
 59   
 
 60   
     public static final String MESSAGES_ENCODING_PROPERTY_NAME = "org.apache.tapestry.messages-encoding";
 61   
 
 62   
     /**
 63   
      * Map of Maps. The outer map is keyed on component specification location (a{@link Resource}.
 64   
      * This inner map is keyed on locale and the value is a {@link Properties}.
 65   
      */
 66   
 
 67   
     private Map _componentCache = new HashMap();
 68   
 
 69   
     private ComponentPropertySource _componentPropertySource;
 70   
 
 71   
     /**
 72   
      * Returns an instance of {@link Properties}containing the properly localized messages for the
 73   
      * component, in the {@link Locale}identified by the component's containing page.
 74   
      */
 75   
 
 76  29
     protected synchronized Properties getLocalizedProperties(IComponent component)
 77   
     {
 78  29
         Defense.notNull(component, "component");
 79   
 
 80  29
         Resource specificationLocation = component.getSpecification().getSpecificationLocation();
 81  29
         Locale locale = component.getPage().getLocale();
 82   
 
 83  29
         Map propertiesMap = findPropertiesMapForResource(specificationLocation);
 84   
 
 85  29
         Properties result = (Properties) propertiesMap.get(locale);
 86   
 
 87  29
         if (result == null)
 88   
         {
 89   
 
 90   
             // Not found, create it now.
 91   
 
 92  28
             result = assembleComponentProperties(
 93   
                     component,
 94   
                     specificationLocation,
 95   
                     propertiesMap,
 96   
                     locale);
 97   
 
 98  28
             propertiesMap.put(locale, result);
 99   
         }
 100   
 
 101  29
         return result;
 102   
     }
 103   
 
 104  57
     private Map findPropertiesMapForResource(Resource resource)
 105   
     {
 106  57
         Map result = (Map) _componentCache.get(resource);
 107   
 
 108  57
         if (result == null)
 109   
         {
 110  46
             result = new HashMap();
 111  46
             _componentCache.put(resource, result);
 112   
         }
 113   
 
 114  57
         return result;
 115   
     }
 116   
 
 117  28
     private Properties getNamespaceProperties(IComponent component, Locale locale)
 118   
     {
 119  28
         INamespace namespace = component.getNamespace();
 120   
 
 121  28
         Resource namespaceLocation = namespace.getSpecificationLocation();
 122   
 
 123  28
         Map propertiesMap = findPropertiesMapForResource(namespaceLocation);
 124   
 
 125  28
         Properties result = (Properties) propertiesMap.get(locale);
 126   
 
 127  28
         if (result == null)
 128   
         {
 129  28
             result = assembleNamespaceProperties(namespace, propertiesMap, locale);
 130   
 
 131  28
             propertiesMap.put(locale, result);
 132   
         }
 133   
 
 134  28
         return result;
 135   
     }
 136   
 
 137  28
     private Properties assembleComponentProperties(IComponent component,
 138   
             Resource baseResourceLocation, Map propertiesMap, Locale locale)
 139   
     {
 140  28
         List localizations = findLocalizationsForResource(baseResourceLocation, locale);
 141   
 
 142  28
         Properties parent = getNamespaceProperties(component, locale);
 143   
 
 144  28
         Iterator i = localizations.iterator();
 145   
 
 146  28
         while (i.hasNext())
 147   
         {
 148  74
             ResourceLocalization rl = (ResourceLocalization) i.next();
 149   
 
 150  74
             Locale l = rl.getLocale();
 151   
 
 152  74
             Properties properties = (Properties) propertiesMap.get(l);
 153   
 
 154  74
             if (properties == null)
 155   
             {
 156  67
                 properties = readComponentProperties(component, l, rl.getResource(), parent);
 157   
 
 158  67
                 propertiesMap.put(l, properties);
 159   
             }
 160   
 
 161  74
             parent = properties;
 162   
         }
 163   
 
 164  28
         return parent;
 165   
     }
 166   
 
 167  28
     private Properties assembleNamespaceProperties(INamespace namespace, Map propertiesMap,
 168   
             Locale locale)
 169   
     {
 170  28
         List localizations = findLocalizationsForResource(
 171   
                 namespace.getSpecificationLocation(),
 172   
                 locale);
 173   
 
 174   
         // Build them back up in reverse order.
 175   
 
 176  28
         Properties parent = _emptyProperties;
 177   
 
 178  28
         Iterator i = localizations.iterator();
 179   
 
 180  28
         while (i.hasNext())
 181   
         {
 182  74
             ResourceLocalization rl = (ResourceLocalization) i.next();
 183   
 
 184  74
             Locale l = rl.getLocale();
 185   
 
 186  74
             Properties properties = (Properties) propertiesMap.get(l);
 187   
 
 188  74
             if (properties == null)
 189   
             {
 190  67
                 properties = readNamespaceProperties(namespace, l, rl.getResource(), parent);
 191   
 
 192  67
                 propertiesMap.put(l, properties);
 193   
             }
 194   
 
 195  74
             parent = properties;
 196   
         }
 197   
 
 198  28
         return parent;
 199   
 
 200   
     }
 201   
 
 202   
     /**
 203   
      * Finds the localizations of the provided resource. Returns a List of
 204   
      * {@link ResourceLocalization}(each pairing a locale with a localized resource). The list is
 205   
      * ordered from most general (i.e., "foo.properties") to most specific (i.e.,
 206   
      * "foo_en_US_yokel.properties").
 207   
      */
 208   
 
 209  56
     private List findLocalizationsForResource(Resource resource, Locale locale)
 210   
     {
 211  56
         List result = new ArrayList();
 212   
 
 213  56
         String baseName = extractBaseName(resource);
 214   
 
 215  56
         LocalizedNameGenerator g = new LocalizedNameGenerator(baseName, locale, SUFFIX);
 216   
 
 217  56
         while (g.more())
 218   
         {
 219  148
             String localizedName = g.next();
 220  148
             Locale l = g.getCurrentLocale();
 221  148
             Resource localizedResource = resource.getRelativeResource(localizedName);
 222   
 
 223  148
             result.add(new ResourceLocalization(l, localizedResource));
 224   
         }
 225   
 
 226  56
         Collections.reverse(result);
 227   
 
 228  56
         return result;
 229   
     }
 230   
 
 231  56
     private String extractBaseName(Resource baseResourceLocation)
 232   
     {
 233  56
         String fileName = baseResourceLocation.getName();
 234  56
         int dotx = fileName.lastIndexOf('.');
 235   
 
 236  56
         return fileName.substring(0, dotx);
 237   
     }
 238   
 
 239  67
     private Properties readComponentProperties(IComponent component, Locale locale,
 240   
             Resource propertiesResource, Properties parent)
 241   
     {
 242  67
         String encoding = getComponentMessagesEncoding(component, locale);
 243   
 
 244  67
         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
 245   
     }
 246   
 
 247  67
     private Properties readNamespaceProperties(INamespace namespace, Locale locale,
 248   
             Resource propertiesResource, Properties parent)
 249   
     {
 250  67
         String encoding = getNamespaceMessagesEncoding(namespace, locale);
 251   
 
 252  67
         return readPropertiesResource(propertiesResource.getResourceURL(), encoding, parent);
 253   
     }
 254   
 
 255  134
     private Properties readPropertiesResource(URL resourceURL, String encoding, Properties parent)
 256   
     {
 257  134
         if (resourceURL == null)
 258  60
             return parent;
 259   
 
 260  74
         Properties result = new Properties(parent);
 261   
 
 262  74
         LocalizedProperties wrapper = new LocalizedProperties(result);
 263   
 
 264  74
         InputStream input = null;
 265   
 
 266  74
         try
 267   
         {
 268  74
             input = new BufferedInputStream(resourceURL.openStream());
 269   
 
 270  74
             if (encoding == null)
 271  70
                 wrapper.load(input);
 272   
             else
 273  4
                 wrapper.load(input, encoding);
 274   
 
 275  74
             input.close();
 276   
         }
 277   
         catch (IOException ex)
 278   
         {
 279  0
             throw new ApplicationRuntimeException(ImplMessages.unableToLoadProperties(
 280   
                     resourceURL,
 281   
                     ex), ex);
 282   
         }
 283   
         finally
 284   
         {
 285  74
             close(input);
 286   
         }
 287   
 
 288  74
         return result;
 289   
     }
 290   
 
 291  74
     private void close(InputStream is)
 292   
     {
 293  74
         if (is != null)
 294  74
             try
 295   
             {
 296  74
                 is.close();
 297   
             }
 298   
             catch (IOException ex)
 299   
             {
 300   
                 // Ignore.
 301   
             }
 302   
     }
 303   
 
 304   
     /**
 305   
      * Clears the cache of read properties files.
 306   
      */
 307   
 
 308  0
     public synchronized void resetEventDidOccur()
 309   
     {
 310  0
         _componentCache.clear();
 311   
     }
 312   
 
 313  29
     public Messages getMessages(IComponent component)
 314   
     {
 315  29
         return new ComponentMessages(component.getPage().getLocale(),
 316   
                 getLocalizedProperties(component));
 317   
     }
 318   
 
 319  67
     private String getComponentMessagesEncoding(IComponent component, Locale locale)
 320   
     {
 321  67
         String encoding = _componentPropertySource.getLocalizedComponentProperty(
 322   
                 component,
 323   
                 locale,
 324   
                 MESSAGES_ENCODING_PROPERTY_NAME);
 325   
 
 326  67
         if (encoding == null)
 327  65
             encoding = _componentPropertySource.getLocalizedComponentProperty(
 328   
                     component,
 329   
                     locale,
 330   
                     TemplateSourceImpl.TEMPLATE_ENCODING_PROPERTY_NAME);
 331   
 
 332  67
         return encoding;
 333   
     }
 334   
 
 335  67
     private String getNamespaceMessagesEncoding(INamespace namespace, Locale locale)
 336   
     {
 337  67
         return _componentPropertySource.getLocalizedNamespaceProperty(
 338   
                 namespace,
 339   
                 locale,
 340   
                 MESSAGES_ENCODING_PROPERTY_NAME);
 341   
     }
 342   
 
 343  23
     public void setComponentPropertySource(ComponentPropertySource componentPropertySource)
 344   
     {
 345  23
         _componentPropertySource = componentPropertySource;
 346   
     }
 347   
 }