Coverage Report - org.apache.tiles.definition.dao.CachingLocaleUrlDefinitionDAO
 
Classes in this File Line Coverage Branch Coverage Complexity
CachingLocaleUrlDefinitionDAO
87%
54/62
63%
23/36
2.583
 
 1  
 /*
 2  
  * $Id: CachingLocaleUrlDefinitionDAO.java 1752405 2016-07-13 12:13:34Z mck $
 3  
  *
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  * http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 package org.apache.tiles.definition.dao;
 23  
 
 24  
 import java.util.HashMap;
 25  
 import java.util.LinkedHashMap;
 26  
 import java.util.Locale;
 27  
 import java.util.Map;
 28  
 
 29  
 import org.apache.tiles.Definition;
 30  
 import org.apache.tiles.definition.pattern.PatternDefinitionResolver;
 31  
 import org.apache.tiles.definition.pattern.PatternDefinitionResolverAware;
 32  
 import org.apache.tiles.request.ApplicationContext;
 33  
 import org.apache.tiles.request.ApplicationResource;
 34  
 import org.apache.tiles.request.locale.LocaleUtil;
 35  
 
 36  
 /**
 37  
  * <p>
 38  
  * A definitions DAO (loading URLs and using Locale as a customization key) that
 39  
  * caches definitions that have been loaded in a raw way (i.e. with inheritance
 40  
  * that is not resolved).
 41  
  * </p>
 42  
  * <p>
 43  
  * It can check if the URLs change, but by default this feature is turned off.
 44  
  * </p>
 45  
  *
 46  
  * @version $Rev: 1752405 $ $Date: 2016-07-13 22:13:34 +1000 (Wed, 13 Jul 2016) $
 47  
  * @since 2.1.0
 48  
  */
 49  0
 public class CachingLocaleUrlDefinitionDAO extends BaseLocaleUrlDefinitionDAO
 50  
         implements PatternDefinitionResolverAware<Locale> {
 51  
 
 52  
     /**
 53  
      * Initialization parameter to set whether we want to refresh URLs when they
 54  
      * change.
 55  
      *
 56  
      * @since 2.1.0
 57  
      */
 58  
     public static final String CHECK_REFRESH_INIT_PARAMETER =
 59  
         "org.apache.tiles.definition.dao.LocaleUrlDefinitionDAO.CHECK_REFRESH";
 60  
 
 61  
     /**
 62  
      * The locale-specific set of definitions objects.
 63  
      *
 64  
      * @since 2.1.0
 65  
      */
 66  
     protected Map<Locale, Map<String, Definition>> locale2definitionMap;
 67  
 
 68  
     /**
 69  
      * Flag that, when <code>true</code>, enables automatic checking of URLs
 70  
      * changing.
 71  
      *
 72  
      * @since 2.1.0
 73  
      */
 74  22
     protected boolean checkRefresh = false;
 75  
 
 76  
     /**
 77  
      * Resolves definitions using patterns.
 78  
      *
 79  
      * @since 2.2.0
 80  
      */
 81  
     protected PatternDefinitionResolver<Locale> definitionResolver;
 82  
 
 83  
     /**
 84  
      * Constructor.
 85  
      *
 86  
      * @since 2.1.0
 87  
      */
 88  
     public CachingLocaleUrlDefinitionDAO(ApplicationContext applicationContext) {
 89  22
         super(applicationContext);
 90  22
         locale2definitionMap = new HashMap<Locale, Map<String, Definition>>();
 91  22
     }
 92  
 
 93  
     /** {@inheritDoc} */
 94  
     public void setPatternDefinitionResolver(
 95  
             PatternDefinitionResolver<Locale> definitionResolver) {
 96  22
         this.definitionResolver = definitionResolver;
 97  22
     }
 98  
 
 99  
     /** {@inheritDoc} */
 100  
     public Definition getDefinition(String name, Locale customizationKey) {
 101  55
         Definition retValue = null;
 102  55
         if (customizationKey == null) {
 103  26
             customizationKey = Locale.ROOT;
 104  
         }
 105  55
         Map<String, Definition> definitions = getDefinitions(customizationKey);
 106  55
         if (definitions != null) {
 107  55
             retValue = definitions.get(name);
 108  
 
 109  55
             if (retValue == null) {
 110  10
                 retValue = getDefinitionFromResolver(name, customizationKey);
 111  
 
 112  10
                 if (retValue != null) {
 113  10
                     synchronized (definitions) {
 114  10
                         definitions.put(name, retValue);
 115  10
                     }
 116  
                 }
 117  
             }
 118  
         }
 119  
 
 120  55
         return retValue;
 121  
     }
 122  
 
 123  
     /** {@inheritDoc} */
 124  
     public Map<String, Definition> getDefinitions(Locale customizationKey) {
 125  65
         if (customizationKey == null) {
 126  2
             customizationKey = Locale.ROOT;
 127  
         }
 128  65
         Map<String, Definition> retValue = locale2definitionMap
 129  
                 .get(customizationKey);
 130  65
         if (retValue == null || (checkRefresh && refreshRequired())) {
 131  28
             retValue = checkAndloadDefinitions(customizationKey);
 132  
         }
 133  65
         return retValue;
 134  
     }
 135  
 
 136  
     /**
 137  
      * Sets the flag to check source refresh. If not called, the default is
 138  
      * <code>false</code>.
 139  
      *
 140  
      * @param checkRefresh When <code>true</code>, enables automatic checking
 141  
      * of sources changing.
 142  
      * @since 2.1.0
 143  
      */
 144  
     public void setCheckRefresh(boolean checkRefresh) {
 145  0
         this.checkRefresh = checkRefresh;
 146  0
     }
 147  
 
 148  
     /**
 149  
      * Returns a definition from the definition resolver.
 150  
      *
 151  
      * @param name The name of the definition.
 152  
      * @param customizationKey The customization key to use.
 153  
      * @return The resolved definition.
 154  
      */
 155  
     protected Definition getDefinitionFromResolver(String name,
 156  
             Locale customizationKey) {
 157  10
         return definitionResolver.resolveDefinition(name,
 158  
                 customizationKey);
 159  
     }
 160  
 
 161  
     /**
 162  
      * Checks if sources have changed. If yes, it clears the cache. Then continues
 163  
      * loading definitions.
 164  
      *
 165  
      * @param customizationKey The locale to use when loading sources.
 166  
      * @return The loaded definitions.
 167  
      * @since 2.1.0
 168  
      */
 169  
     protected synchronized Map<String, Definition> checkAndloadDefinitions(Locale customizationKey) {
 170  28
         Map<String, Definition> existingDefinitions = locale2definitionMap.get(customizationKey);
 171  28
         boolean definitionsAlreadyLoaded = existingDefinitions != null;
 172  28
         if (definitionsAlreadyLoaded) {
 173  0
             return existingDefinitions;
 174  
         }
 175  28
         if (checkRefresh && refreshRequired()) {
 176  0
             locale2definitionMap.clear();
 177  0
             definitionResolver.clearPatternPaths(customizationKey);
 178  
         }
 179  28
         loadDefinitions(customizationKey);
 180  28
         return locale2definitionMap.get(customizationKey);
 181  
     }
 182  
 
 183  
     /**
 184  
      * Tries to load definitions if necessary.
 185  
      *
 186  
      * @param customizationKey The locale to use when loading sources.
 187  
      * @return The loaded definitions.
 188  
      * @since 2.1.0
 189  
      */
 190  
     protected Map<String, Definition> loadDefinitions(Locale customizationKey) {
 191  28
         Map<String, Definition> localeDefsMap = locale2definitionMap
 192  
                 .get(customizationKey);
 193  28
         if (localeDefsMap != null) {
 194  0
             return localeDefsMap;
 195  
         }
 196  
 
 197  28
         return loadDefinitionsFromResources(customizationKey);
 198  
     }
 199  
 
 200  
     /**
 201  
      * Loads definitions from the sources.
 202  
      *
 203  
      * @param customizationKey The locale to use when loading Resources.
 204  
      * @return The loaded definitions.
 205  
      * @since 2.1.0
 206  
      */
 207  
     protected Map<String, Definition> loadDefinitionsFromResources(Locale customizationKey) {
 208  28
         Map<String, Definition> localeDefsMap = loadRawDefinitionsFromResources(customizationKey);
 209  28
         Map<String, Definition> defsMap = definitionResolver
 210  
                 .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
 211  
                         customizationKey);
 212  28
         locale2definitionMap.put(customizationKey, defsMap);
 213  28
         return localeDefsMap;
 214  
     }
 215  
 
 216  
     /**
 217  
      * Loads the raw definitions from the sources associated with a locale.
 218  
      *
 219  
      * @param customizationKey The locale to use when loading Resources.
 220  
      * @return The loaded definitions.
 221  
      * @since 2.1.3
 222  
      */
 223  
     protected Map<String, Definition> loadRawDefinitionsFromResources(
 224  
             Locale customizationKey) {
 225  
         Map<String, Definition> localeDefsMap;
 226  
 
 227  64
         Locale parentLocale = LocaleUtil.getParentLocale(customizationKey);
 228  64
         localeDefsMap = new LinkedHashMap<String, Definition>();
 229  64
         if (parentLocale != null) {
 230  36
             Map<String, Definition> parentDefs = loadRawDefinitionsFromResources(parentLocale);
 231  36
             if (parentDefs != null) {
 232  36
                 localeDefsMap.putAll(parentDefs);
 233  
             }
 234  
         }
 235  
         // For each source, the resource must be loaded.
 236  64
         for (ApplicationResource resource : sources) {
 237  160
             ApplicationResource newResource = applicationContext.getResource(resource, customizationKey);
 238  160
             if (newResource != null) {
 239  86
                 Map<String, Definition> defsMap = loadDefinitionsFromResource(newResource);
 240  86
                 if (defsMap != null) {
 241  86
                     localeDefsMap.putAll(defsMap);
 242  
                 }
 243  
             }
 244  160
         }
 245  64
         return localeDefsMap;
 246  
     }
 247  
 
 248  
     /**
 249  
      * Loads parent definitions, i.e. definitions mapped to a parent locale.
 250  
      *
 251  
      * @param parentLocale The locale to use when loading URLs.
 252  
      * @return The loaded parent definitions.
 253  
      * @since 2.1.0
 254  
      */
 255  
     protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
 256  0
         return loadDefinitions(parentLocale);
 257  
     }
 258  
 
 259  
     /**
 260  
      * Copies the definition map to be passed to a higher level of customization
 261  
      * key.
 262  
      *
 263  
      * @param localeDefsMap The map of definition to be copied.
 264  
      * @return The copy of the definition map. This particular implementation
 265  
      * return the <code>localeDefsMap</code> itself.
 266  
      * @since 2.1.4
 267  
      */
 268  
     protected Map<String, Definition> copyDefinitionMap(
 269  
             Map<String, Definition> localeDefsMap) {
 270  14
         return localeDefsMap;
 271  
     }
 272  
 }