1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 }
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
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
142 alreadyResolvedDefinitions.add(definition.getName());
143
144
145 Definition parent = definitions.get(definition.getExtends());
146 if (parent == null) {
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
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 }