Project Tiles has retired. For details please refer to its Attic page.
CachingLocaleUrlDefinitionDAO xref
View Javadoc

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  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      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          super(applicationContext);
90          locale2definitionMap = new HashMap<Locale, Map<String, Definition>>();
91      }
92  
93      /** {@inheritDoc} */
94      public void setPatternDefinitionResolver(
95              PatternDefinitionResolver<Locale> definitionResolver) {
96          this.definitionResolver = definitionResolver;
97      }
98  
99      /** {@inheritDoc} */
100     public Definition getDefinition(String name, Locale customizationKey) {
101         Definition retValue = null;
102         if (customizationKey == null) {
103             customizationKey = Locale.ROOT;
104         }
105         Map<String, Definition> definitions = getDefinitions(customizationKey);
106         if (definitions != null) {
107             retValue = definitions.get(name);
108 
109             if (retValue == null) {
110                 retValue = getDefinitionFromResolver(name, customizationKey);
111 
112                 if (retValue != null) {
113                     synchronized (definitions) {
114                         definitions.put(name, retValue);
115                     }
116                 }
117             }
118         }
119 
120         return retValue;
121     }
122 
123     /** {@inheritDoc} */
124     public Map<String, Definition> getDefinitions(Locale customizationKey) {
125         if (customizationKey == null) {
126             customizationKey = Locale.ROOT;
127         }
128         Map<String, Definition> retValue = locale2definitionMap
129                 .get(customizationKey);
130         if (retValue == null || (checkRefresh && refreshRequired())) {
131             retValue = checkAndloadDefinitions(customizationKey);
132         }
133         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         this.checkRefresh = checkRefresh;
146     }
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         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         Map<String, Definition> existingDefinitions = locale2definitionMap.get(customizationKey);
171         boolean definitionsAlreadyLoaded = existingDefinitions != null;
172         if (definitionsAlreadyLoaded) {
173             return existingDefinitions;
174         }
175         if (checkRefresh && refreshRequired()) {
176             locale2definitionMap.clear();
177             definitionResolver.clearPatternPaths(customizationKey);
178         }
179         loadDefinitions(customizationKey);
180         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         Map<String, Definition> localeDefsMap = locale2definitionMap
192                 .get(customizationKey);
193         if (localeDefsMap != null) {
194             return localeDefsMap;
195         }
196 
197         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         Map<String, Definition> localeDefsMap = loadRawDefinitionsFromResources(customizationKey);
209         Map<String, Definition> defsMap = definitionResolver
210                 .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
211                         customizationKey);
212         locale2definitionMap.put(customizationKey, defsMap);
213         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         Locale parentLocale = LocaleUtil.getParentLocale(customizationKey);
228         localeDefsMap = new LinkedHashMap<String, Definition>();
229         if (parentLocale != null) {
230             Map<String, Definition> parentDefs = loadRawDefinitionsFromResources(parentLocale);
231             if (parentDefs != null) {
232                 localeDefsMap.putAll(parentDefs);
233             }
234         }
235         // For each source, the resource must be loaded.
236         for (ApplicationResource resource : sources) {
237             ApplicationResource newResource = applicationContext.getResource(resource, customizationKey);
238             if (newResource != null) {
239                 Map<String, Definition> defsMap = loadDefinitionsFromResource(newResource);
240                 if (defsMap != null) {
241                     localeDefsMap.putAll(defsMap);
242                 }
243             }
244         }
245         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         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         return localeDefsMap;
271     }
272 }