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

1   /*
2    * $Id: ResolvingLocaleUrlDefinitionDAO.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.util.HashSet;
25  import java.util.LinkedHashMap;
26  import java.util.Locale;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.tiles.Definition;
31  import org.apache.tiles.definition.NoSuchDefinitionException;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /***
36   * <p>
37   * A definitions DAO (loading URLs and using Locale as a customization key) that
38   * caches definitions that have been loaded and resolves inheritances.
39   * </p>
40   * <p>
41   * It can check if the URLs change, but by default this feature is turned off.
42   * </p>
43   *
44   * @version $Rev: 823662 $ $Date: 2009-10-09 20:48:03 +0200 (ven, 09 ott 2009) $
45   * @since 2.1.0
46   */
47  public class ResolvingLocaleUrlDefinitionDAO extends
48          CachingLocaleUrlDefinitionDAO {
49  
50      /***
51       * The logging object.
52       */
53      private final Logger log = LoggerFactory.getLogger(ResolvingLocaleUrlDefinitionDAO.class);
54  
55      /*** {@inheritDoc} */
56      @Override
57      protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
58          return loadDefinitionsFromURLs(parentLocale);
59      }
60  
61      /*** {@inheritDoc} */
62      @Override
63      protected Map<String, Definition> loadDefinitionsFromURLs(
64              Locale customizationKey) {
65          Map<String, Definition> retValue = super.loadDefinitionsFromURLs(customizationKey);
66          Map<String, Definition> defsMap = locale2definitionMap.get(customizationKey);
67          resolveInheritances(defsMap, customizationKey);
68          return retValue;
69      }
70  
71      /*** {@inheritDoc} */
72      @Override
73      protected Definition getDefinitionFromResolver(String name,
74              Locale customizationKey) {
75          Definition retValue = super.getDefinitionFromResolver(name, customizationKey);
76          if (retValue != null && retValue.getExtends() != null) {
77              Definition parent = getDefinition(retValue.getExtends(), customizationKey);
78              retValue.inherit(parent);
79          }
80  
81          return retValue;
82      }
83  
84      /*** {@inheritDoc} */
85      @Override
86      @Deprecated
87      protected void postDefinitionLoadOperations(
88              Map<String, Definition> localeDefsMap, Locale customizationKey) {
89          resolveInheritances(localeDefsMap, customizationKey);
90          super.postDefinitionLoadOperations(localeDefsMap, customizationKey);
91      }
92  
93      /***
94       * Resolve locale-specific extended instances.
95       *
96       * @param map The definition map containing the definitions to resolve.
97       * @param locale The locale to use.
98       * @throws NoSuchDefinitionException If a parent definition is not found.
99       * @since 2.1.0
100      */
101     protected void resolveInheritances(Map<String, Definition> map, Locale locale) {
102         if (map != null) {
103             Set<String> alreadyResolvedDefinitions = new HashSet<String>();
104             for (Definition definition : map.values()) {
105                 resolveInheritance(definition, map, locale,
106                         alreadyResolvedDefinitions);
107             }  // end loop
108         }
109     }
110 
111     /***
112      * Resolve locale-specific inheritance. First, resolve parent's inheritance,
113      * then set template to the parent's template. Also copy attributes setted
114      * in parent, and not set in child If instance doesn't extend anything, do
115      * nothing.
116      *
117      * @param definition The definition to resolve
118      * @param definitions The definitions to take when obtaining a parent
119      * definition.
120      * @param locale The locale to use.
121      * @param alreadyResolvedDefinitions The set of the definitions that have
122      * been already resolved.
123      * @throws NoSuchDefinitionException If an inheritance can not be solved.
124      * @since 2.1.0
125      */
126     protected void resolveInheritance(Definition definition,
127             Map<String, Definition> definitions, Locale locale,
128             Set<String> alreadyResolvedDefinitions) {
129         // Already done, or not needed ?
130         if (!definition.isExtending()
131                 || alreadyResolvedDefinitions.contains(definition.getName())) {
132             return;
133         }
134 
135         if (log.isDebugEnabled()) {
136             log.debug("Resolve definition for child name='"
137                 + definition.getName()
138                 + "' extends='" + definition.getExtends() + "'.");
139         }
140 
141         // Set as visited to avoid endless recurisvity.
142         alreadyResolvedDefinitions.add(definition.getName());
143 
144         // Resolve parent before itself.
145         Definition parent = definitions.get(definition.getExtends());
146         if (parent == null) { // error
147             String msg = "Error while resolving definition inheritance: child '"
148                 + definition.getName()
149                 + "' can't find its ancestor '"
150                 + definition.getExtends()
151                 + "'. Please check your description file.";
152             // to do : find better exception
153             throw new NoSuchDefinitionException(msg);
154         }
155 
156         resolveInheritance(parent, definitions, locale,
157                 alreadyResolvedDefinitions);
158 
159         definition.inherit(parent);
160     }
161 
162     /***
163      * Copies the definition map to be passed to a higher level of customization
164      * key.
165      *
166      * @param localeDefsMap The map of definition to be copied.
167      * @return The copy of the definition map. This particular implementation
168      * deep-copies the <code>localeDefsMap</code> into a {@link LinkedHashMap}.
169      * @since 2.1.4
170      */
171     @Override
172     protected Map<String, Definition> copyDefinitionMap(
173             Map<String, Definition> localeDefsMap) {
174         Map<String, Definition> retValue = new LinkedHashMap<String, Definition>(
175                 localeDefsMap.size());
176 
177         for (Map.Entry<String, Definition> entry : localeDefsMap.entrySet()) {
178             Definition definition = new Definition(entry.getValue());
179             retValue.put(entry.getKey(), definition);
180         }
181 
182         return retValue;
183     }
184 }