This project has retired. For details please refer to its Attic page.
CachingLocaleUrlDefinitionDAO xref
View Javadoc

1   /*
2    * $Id: CachingLocaleUrlDefinitionDAO.java 823662 2009-10-09 18:48:03Z apetrelli $
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.net.MalformedURLException;
25  import java.net.URL;
26  import java.util.HashMap;
27  import java.util.LinkedHashMap;
28  import java.util.Locale;
29  import java.util.Map;
30  
31  import org.apache.tiles.Definition;
32  import org.apache.tiles.definition.DefinitionsFactoryException;
33  import org.apache.tiles.definition.NoSuchDefinitionException;
34  import org.apache.tiles.definition.Refreshable;
35  import org.apache.tiles.definition.pattern.BasicPatternDefinitionResolver;
36  import org.apache.tiles.definition.pattern.PatternDefinitionResolver;
37  import org.apache.tiles.definition.pattern.PatternDefinitionResolverAware;
38  import org.apache.tiles.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory;
39  import org.apache.tiles.util.LocaleUtil;
40  
41  /***
42   * <p>
43   * A definitions DAO (loading URLs and using Locale as a customization key) that
44   * caches definitions that have been loaded in a raw way (i.e. with inheritance
45   * that is not resolved).
46   * </p>
47   * <p>
48   * It can check if the URLs change, but by default this feature is turned off.
49   * </p>
50   *
51   * @version $Rev: 823662 $ $Date: 2009-10-09 20:48:03 +0200 (ven, 09 ott 2009) $
52   * @since 2.1.0
53   */
54  public class CachingLocaleUrlDefinitionDAO extends BaseLocaleUrlDefinitionDAO
55          implements Refreshable, PatternDefinitionResolverAware<Locale> {
56  
57      /***
58       * Initialization parameter to set whether we want to refresh URLs when they
59       * change.
60       *
61       * @since 2.1.0
62       */
63      public static final String CHECK_REFRESH_INIT_PARAMETER =
64          "org.apache.tiles.definition.dao.LocaleUrlDefinitionDAO.CHECK_REFRESH";
65  
66      /***
67       * The locale-specific set of definitions objects.
68       *
69       * @since 2.1.0
70       */
71      protected Map<Locale, Map<String, Definition>> locale2definitionMap;
72  
73      /***
74       * Flag that, when <code>true</code>, enables automatic checking of URLs
75       * changing.
76       *
77       * @since 2.1.0
78       */
79      protected boolean checkRefresh = false;
80  
81      /***
82       * Resolves definitions using patterns.
83       *
84       * @since 2.2.0
85       */
86      protected PatternDefinitionResolver<Locale> definitionResolver;
87  
88      /***
89       * Constructor.
90       *
91       * @since 2.1.0
92       */
93      public CachingLocaleUrlDefinitionDAO() {
94          locale2definitionMap = new HashMap<Locale, Map<String, Definition>>();
95      }
96  
97      /*** {@inheritDoc} */
98      @Override
99      public void init(Map<String, String> params) {
100         super.init(params);
101 
102         String param = params.get(CHECK_REFRESH_INIT_PARAMETER);
103         checkRefresh = "true".equals(param);
104         WildcardDefinitionPatternMatcherFactory definitionPatternMatcherFactory =
105             new WildcardDefinitionPatternMatcherFactory();
106         definitionResolver = new BasicPatternDefinitionResolver<Locale>(
107                 definitionPatternMatcherFactory,
108                 definitionPatternMatcherFactory);
109     }
110 
111     /*** {@inheritDoc} */
112     public void setPatternDefinitionResolver(
113             PatternDefinitionResolver<Locale> definitionResolver) {
114         this.definitionResolver = definitionResolver;
115     }
116 
117     /*** {@inheritDoc} */
118     public Definition getDefinition(String name, Locale customizationKey) {
119         Definition retValue = null;
120         if (customizationKey == null) {
121             customizationKey = LocaleUtil.NULL_LOCALE;
122         }
123         Map<String, Definition> definitions = getDefinitions(customizationKey);
124         if (definitions != null) {
125             retValue = definitions.get(name);
126 
127             if (retValue == null) {
128                 retValue = getDefinitionFromResolver(name, customizationKey);
129 
130                 if (retValue != null) {
131                     try {
132                         synchronized (definitions) {
133                             definitions.put(name, retValue);
134                         }
135                     } catch (NoSuchDefinitionException ex) {
136                         throw new IllegalStateException(
137                                 "Unable to resolve wildcard mapping", ex);
138                     }
139                 }
140             }
141         }
142 
143         return retValue;
144     }
145 
146     /*** {@inheritDoc} */
147     public Map<String, Definition> getDefinitions(Locale customizationKey) {
148         if (customizationKey == null) {
149             customizationKey = LocaleUtil.NULL_LOCALE;
150         }
151         Map<String, Definition> retValue = locale2definitionMap
152                 .get(customizationKey);
153         if (retValue == null || (checkRefresh && refreshRequired())) {
154             retValue = checkAndloadDefinitions(customizationKey);
155         }
156         return retValue;
157     }
158 
159     /*** {@inheritDoc} */
160     public synchronized void refresh() {
161         if (refreshRequired()) {
162             locale2definitionMap.clear();
163         }
164     }
165 
166     /***
167      * Sets the flag to check URL refresh. If not called, the default is
168      * <code>false</code>.
169      *
170      * @param checkRefresh When <code>true</code>, enables automatic checking
171      * of URLs changing.
172      * @since 2.1.0
173      */
174     public void setCheckRefresh(boolean checkRefresh) {
175         this.checkRefresh = checkRefresh;
176     }
177 
178     /***
179      * Returns a definition from the definition resolver.
180      *
181      * @param name The name of the definition.
182      * @param customizationKey The customization key to use.
183      * @return The resolved definition.
184      */
185     protected Definition getDefinitionFromResolver(String name,
186             Locale customizationKey) {
187         return definitionResolver.resolveDefinition(name,
188                 customizationKey);
189     }
190 
191     /***
192      * Checks if URLs have changed. If yes, it clears the cache. Then continues
193      * loading definitions.
194      *
195      * @param customizationKey The locale to use when loading URLs.
196      * @return The loaded definitions.
197      * @since 2.1.0
198      */
199     protected synchronized Map<String, Definition> checkAndloadDefinitions(
200             Locale customizationKey) {
201         if (checkRefresh && refreshRequired()) {
202             locale2definitionMap.clear();
203         }
204         loadDefinitions(customizationKey);
205         return locale2definitionMap.get(customizationKey);
206     }
207 
208     /***
209      * Tries to load definitions if necessary.
210      *
211      * @param customizationKey The locale to use when loading URLs.
212      * @return The loaded definitions.
213      * @since 2.1.0
214      */
215     protected Map<String, Definition> loadDefinitions(Locale customizationKey) {
216         Map<String, Definition> localeDefsMap = locale2definitionMap
217                 .get(customizationKey);
218         if (localeDefsMap != null) {
219             return localeDefsMap;
220         }
221 
222         return loadDefinitionsFromURLs(customizationKey);
223     }
224 
225     /***
226      * Loads definitions from the URLs.
227      *
228      * @param customizationKey The locale to use when loading URLs.
229      * @return The loaded definitions.
230      * @since 2.1.0
231      */
232     protected Map<String, Definition> loadDefinitionsFromURLs(Locale customizationKey) {
233         Map<String, Definition> localeDefsMap;
234 
235         String postfix = LocaleUtil.calculatePostfix(customizationKey);
236         Locale parentLocale = LocaleUtil.getParentLocale(customizationKey);
237         localeDefsMap = new LinkedHashMap<String, Definition>();
238         if (parentLocale != null) {
239             Map<String, Definition> parentDefs = loadParentDefinitions(parentLocale);
240             if (parentDefs != null) {
241                 localeDefsMap.putAll(parentDefs);
242             }
243         }
244         // For each source, the URL must be loaded.
245         for (URL url : sourceURLs) {
246             String path = url.toExternalForm();
247 
248             String newPath = LocaleUtil.concatPostfix(path, postfix);
249             try {
250                 URL newUrl = new URL(newPath);
251                 Map<String, Definition> defsMap = loadDefinitionsFromURL(newUrl);
252                 if (defsMap != null) {
253                     localeDefsMap.putAll(defsMap);
254                 }
255             } catch (MalformedURLException e) {
256                 throw new DefinitionsFactoryException("Error parsing URL "
257                         + newPath, e);
258             }
259         }
260         Map<String, Definition> defsMap = definitionResolver
261                 .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
262                         customizationKey);
263         locale2definitionMap.put(customizationKey, defsMap);
264         return localeDefsMap;
265     }
266 
267     /***
268      * Loads the raw definitions from the URLs associated with a locale.
269      *
270      * @param customizationKey The locale to use when loading URLs.
271      * @return The loaded definitions.
272      * @since 2.1.3
273      * @deprecated Use {@link #loadDefinitionsFromURLs(Locale)}.
274      */
275     protected Map<String, Definition> loadRawDefinitionsFromURLs(
276             Locale customizationKey) {
277         return loadDefinitionsFromURLs(customizationKey);
278     }
279 
280     /***
281      * Loads parent definitions, i.e. definitions mapped to a parent locale.
282      *
283      * @param parentLocale The locale to use when loading URLs.
284      * @return The loaded parent definitions.
285      * @since 2.1.0
286      */
287     protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
288         return loadDefinitions(parentLocale);
289     }
290 
291     /***
292      * Operations to be done after definitions are loaded.
293      *
294      * @param localeDefsMap The loaded definitions.
295      * @param customizationKey The locale to use when loading URLs.
296      * @since 2.1.0
297      * @deprecated Never used.
298      */
299     protected void postDefinitionLoadOperations(
300             Map<String, Definition> localeDefsMap, Locale customizationKey) {
301 
302         definitionResolver.storeDefinitionPatterns(localeDefsMap, customizationKey);
303     }
304 
305     /***
306      * Copies the definition map to be passed to a higher level of customization
307      * key.
308      *
309      * @param localeDefsMap The map of definition to be copied.
310      * @return The copy of the definition map. This particular implementation
311      * return the <code>localeDefsMap</code> itself.
312      * @since 2.1.4
313      */
314     protected Map<String, Definition> copyDefinitionMap(
315             Map<String, Definition> localeDefsMap) {
316         return localeDefsMap;
317     }
318 }