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;
23
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.Locale;
27 import java.util.Map;
28 import java.util.Set;
29
30 import org.apache.tiles.Attribute;
31 import org.apache.tiles.Definition;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /***
36 * @version $Rev: 791161 $ $Date: 2009-07-04 20:53:36 +0200 (sab, 04 lug 2009) $
37 *
38 * @deprecated This class is, in fact, part of the implementation of
39 * {@link UrlDefinitionsFactory} and
40 * {@link org.apache.tiles.definition.dao.ResolvingLocaleUrlDefinitionDAO}.
41 */
42 @Deprecated
43 public class DefinitionsImpl implements Definitions {
44
45 /***
46 * Commons Logging instance.
47 */
48 private final Logger log = LoggerFactory.getLogger(DefinitionsImpl.class);
49
50 /***
51 * The base set of Definition objects not discriminated by locale.
52 */
53 private Map<String, Definition> baseDefinitions;
54 /***
55 * The locale-specific set of definitions objects.
56 */
57 private Map<Locale, Map<String, Definition>> localeSpecificDefinitions;
58
59 /***
60 * Creates a new instance of DefinitionsImpl.
61 */
62 public DefinitionsImpl() {
63 baseDefinitions = new HashMap<String, Definition>();
64 localeSpecificDefinitions =
65 new HashMap<Locale, Map<String, Definition>>();
66 }
67
68 /***
69 * Creates a new instance of DefinitionsImpl to be used as a wrapper.
70 *
71 * @param baseDefinitions The base definitions to use.
72 * @param localeSpecificDefinitions Maps a locale to a map of definitions.
73 */
74 public DefinitionsImpl(Map<String, Definition> baseDefinitions,
75 Map<Locale, Map<String, Definition>> localeSpecificDefinitions) {
76 this.baseDefinitions = baseDefinitions;
77 this.localeSpecificDefinitions = localeSpecificDefinitions;
78 }
79
80 /***
81 * Returns a Definition object that matches the given name.
82 *
83 * @param name The name of the Definition to return.
84 * @return the Definition matching the given name or null if none
85 * is found.
86 */
87 public Definition getDefinition(String name) {
88 return baseDefinitions.get(name);
89 }
90
91 /***
92 * Adds new Definition objects to the internal collection and
93 * resolves inheritance attraibutes.
94 *
95 * @param defsMap The new definitions to add.
96 * @throws NoSuchDefinitionException If something goes wrong during
97 * addition.
98 */
99 public void addDefinitions(Map<String, Definition> defsMap) {
100 this.baseDefinitions.putAll(defsMap);
101 resolveInheritances();
102 }
103
104 /***
105 * Adds new locale-specific Definition objects to the internal
106 * collection and resolves inheritance attraibutes.
107 *
108 * @param defsMap The new definitions to add.
109 * @param locale The locale to add the definitions to.
110 * @throws NoSuchDefinitionException If something goes wrong during
111 * inheritance resolution.
112 */
113 public void addDefinitions(Map<String, Definition> defsMap,
114 Locale locale) {
115 localeSpecificDefinitions.put(locale, defsMap);
116 resolveInheritances(locale);
117 }
118
119 /***
120 * Returns a Definition object that matches the given name and locale.
121 *
122 * @param name The name of the Definition to return.
123 * @param locale The locale to use to resolve the definition.
124 * @return the Definition matching the given name or null if none
125 * is found.
126 */
127 public Definition getDefinition(String name, Locale locale) {
128 Definition definition = null;
129
130 if (locale != null) {
131 Map<String, Definition> localeSpecificMap =
132 localeSpecificDefinitions.get(locale);
133 if (localeSpecificMap != null) {
134 definition = localeSpecificMap.get(name);
135 }
136 }
137
138 if (definition == null) {
139 definition = getDefinition(name);
140 }
141
142 return definition;
143 }
144
145 /***
146 * Resolve extended instances.
147 *
148 * @throws NoSuchDefinitionException If a parent definition is not found.
149 */
150 public void resolveInheritances() {
151 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
152
153 for (Definition definition : baseDefinitions.values()) {
154 resolveInheritance(definition, null, alreadyResolvedDefinitions);
155 }
156 }
157
158 /***
159 * Resolve locale-specific extended instances.
160 *
161 * @param locale The locale to use.
162 * @throws NoSuchDefinitionException If a parent definition is not found.
163 */
164 public void resolveInheritances(Locale locale) {
165 resolveInheritances();
166
167 Map<String, Definition> map = localeSpecificDefinitions.get(locale);
168 if (map != null) {
169 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
170 for (Definition definition : map.values()) {
171 resolveInheritance(definition, locale,
172 alreadyResolvedDefinitions);
173 }
174 }
175 }
176
177 /***
178 * Clears definitions.
179 */
180 public void reset() {
181 this.baseDefinitions = new HashMap<String, Definition>();
182 this.localeSpecificDefinitions =
183 new HashMap<Locale, Map<String, Definition>>();
184 }
185
186 /***
187 * Returns base definitions collection.
188 *
189 * @return The base (i.e. not depending on any locale) definitions map.
190 */
191 public Map<String, Definition> getBaseDefinitions() {
192 return baseDefinitions;
193 }
194
195 /***
196 * Searches for a definition specified as an attribute.
197 *
198 * @param attr The attribute to use.
199 * @param locale The locale to search into.
200 * @return The required definition if found, otherwise it returns
201 * <code>null</code>.
202 */
203 protected Definition getDefinitionByAttribute(
204 Attribute attr, Locale locale) {
205 Definition retValue = null;
206
207 Object attrValue = attr.getValue();
208 if (attrValue instanceof String) {
209 retValue = this.getDefinition((String) attr
210 .getValue(), locale);
211 }
212
213 return retValue;
214 }
215
216 /***
217 * Resolve locale-specific inheritance.
218 * First, resolve parent's inheritance, then set template to the parent's
219 * template.
220 * Also copy attributes setted in parent, and not set in child
221 * If instance doesn't extend anything, do nothing.
222 *
223 * @param definition The definition to resolve
224 * @param locale The locale to use.
225 * @param alreadyResolvedDefinitions The set of the definitions that have
226 * been already resolved.
227 * @throws NoSuchDefinitionException If an inheritance can not be solved.
228 */
229 protected void resolveInheritance(Definition definition, Locale locale,
230 Set<String> alreadyResolvedDefinitions) {
231
232 if (!definition.isExtending()
233 || alreadyResolvedDefinitions.contains(definition.getName())) {
234 return;
235 }
236
237 if (log.isDebugEnabled()) {
238 log.debug("Resolve definition for child name='"
239 + definition.getName()
240 + "' extends='" + definition.getExtends() + "'.");
241 }
242
243
244 alreadyResolvedDefinitions.add(definition.getName());
245
246
247 Definition parent = getDefinition(definition.getExtends(),
248 locale);
249 if (parent == null) {
250 String msg = "Error while resolving definition inheritance: child '"
251 + definition.getName()
252 + "' can't find its ancestor '"
253 + definition.getExtends()
254 + "'. Please check your description file.";
255 log.error(msg);
256
257 throw new NoSuchDefinitionException(msg);
258 }
259
260 resolveInheritance(parent, locale, alreadyResolvedDefinitions);
261
262 definition.inherit(parent);
263 }
264
265 /***
266 * Overloads a child definition with a given parent.
267 * All attributes present in child are kept. All missing attributes are
268 * copied from the parent.
269 * Special attribute 'template','role' and 'extends' are overloaded in child
270 * if not defined
271 *
272 * @param parent The parent definition.
273 * @param child The child that will be overloaded.
274 * @deprecated Use {@link Definition#inherit(org.apache.tiles.AttributeContext)}.
275 */
276 @Deprecated
277 protected void overload(Definition parent, Definition child) {
278 child.inherit(parent);
279 }
280 }