1/*2 * $Id: DefinitionsImpl.java 791161 2009-07-04 18:53:36Z apetrelli $3 *4 * Licensed to the Apache Software Foundation (ASF) under one5 * or more contributor license agreements. See the NOTICE file6 * distributed with this work for additional information7 * regarding copyright ownership. The ASF licenses this file8 * to you under the Apache License, Version 2.0 (the9 * "License"); you may not use this file except in compliance10 * with the License. You may obtain a copy of the License at11 *12 * http://www.apache.org/licenses/LICENSE-2.013 *14 * Unless required by applicable law or agreed to in writing,15 * software distributed under the License is distributed on an16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY17 * KIND, either express or implied. See the License for the18 * specific language governing permissions and limitations19 * under the License.20 */2122package org.apache.tiles.definition;
2324import java.util.HashMap;
25import java.util.HashSet;
26import java.util.Locale;
27import java.util.Map;
28import java.util.Set;
2930import org.apache.tiles.Attribute;
31import org.apache.tiles.Definition;
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
3435/***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 of39 * {@link UrlDefinitionsFactory} and40 * {@link org.apache.tiles.definition.dao.ResolvingLocaleUrlDefinitionDAO}.41 */42 @Deprecated
43publicclassDefinitionsImpl implements Definitions {
4445/***46 * Commons Logging instance.47 */48privatefinal Logger log = LoggerFactory.getLogger(DefinitionsImpl.class);
4950/***51 * The base set of Definition objects not discriminated by locale.52 */53private Map<String, Definition> baseDefinitions;
54/***55 * The locale-specific set of definitions objects.56 */57private Map<Locale, Map<String, Definition>> localeSpecificDefinitions;
5859/***60 * Creates a new instance of DefinitionsImpl.61 */62publicDefinitionsImpl() {
63 baseDefinitions = new HashMap<String, Definition>();
64 localeSpecificDefinitions =
65new HashMap<Locale, Map<String, Definition>>();
66 }
6768/***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 */74publicDefinitionsImpl(Map<String, Definition> baseDefinitions,
75 Map<Locale, Map<String, Definition>> localeSpecificDefinitions) {
76this.baseDefinitions = baseDefinitions;
77this.localeSpecificDefinitions = localeSpecificDefinitions;
78 }
7980/***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 none85 * is found.86 */87public Definition getDefinition(String name) {
88return baseDefinitions.get(name);
89 }
9091/***92 * Adds new Definition objects to the internal collection and93 * resolves inheritance attraibutes.94 *95 * @param defsMap The new definitions to add.96 * @throws NoSuchDefinitionException If something goes wrong during97 * addition.98 */99publicvoid addDefinitions(Map<String, Definition> defsMap) {
100this.baseDefinitions.putAll(defsMap);
101 resolveInheritances();
102 }
103104/***105 * Adds new locale-specific Definition objects to the internal106 * 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 during111 * inheritance resolution.112 */113publicvoid addDefinitions(Map<String, Definition> defsMap,
114 Locale locale) {
115 localeSpecificDefinitions.put(locale, defsMap);
116 resolveInheritances(locale);
117 }
118119/***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 none125 * is found.126 */127public Definition getDefinition(String name, Locale locale) {
128 Definition definition = null;
129130if (locale != null) {
131 Map<String, Definition> localeSpecificMap =
132 localeSpecificDefinitions.get(locale);
133if (localeSpecificMap != null) {
134 definition = localeSpecificMap.get(name);
135 }
136 }
137138if (definition == null) {
139 definition = getDefinition(name);
140 }
141142return definition;
143 }
144145/***146 * Resolve extended instances.147 *148 * @throws NoSuchDefinitionException If a parent definition is not found.149 */150publicvoid resolveInheritances() {
151 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
152153for (Definition definition : baseDefinitions.values()) {
154 resolveInheritance(definition, null, alreadyResolvedDefinitions);
155 } // end loop156 }
157158/***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 */164publicvoid resolveInheritances(Locale locale) {
165 resolveInheritances();
166167 Map<String, Definition> map = localeSpecificDefinitions.get(locale);
168if (map != null) {
169 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
170for (Definition definition : map.values()) {
171 resolveInheritance(definition, locale,
172 alreadyResolvedDefinitions);
173 } // end loop174 }
175 }
176177/***178 * Clears definitions.179 */180publicvoid reset() {
181this.baseDefinitions = new HashMap<String, Definition>();
182this.localeSpecificDefinitions =
183new HashMap<Locale, Map<String, Definition>>();
184 }
185186/***187 * Returns base definitions collection.188 *189 * @return The base (i.e. not depending on any locale) definitions map.190 */191public Map<String, Definition> getBaseDefinitions() {
192return baseDefinitions;
193 }
194195/***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 returns201 * <code>null</code>.202 */203protected Definition getDefinitionByAttribute(
204 Attribute attr, Locale locale) {
205 Definition retValue = null;
206207 Object attrValue = attr.getValue();
208if (attrValue instanceof String) {
209 retValue = this.getDefinition((String) attr
210 .getValue(), locale);
211 }
212213return retValue;
214 }
215216/***217 * Resolve locale-specific inheritance.218 * First, resolve parent's inheritance, then set template to the parent's219 * template.220 * Also copy attributes setted in parent, and not set in child221 * If instance doesn't extend anything, do nothing.222 *223 * @param definition The definition to resolve224 * @param locale The locale to use.225 * @param alreadyResolvedDefinitions The set of the definitions that have226 * been already resolved.227 * @throws NoSuchDefinitionException If an inheritance can not be solved.228 */229protectedvoid resolveInheritance(Definition definition, Locale locale,
230 Set<String> alreadyResolvedDefinitions) {
231// Already done, or not needed ?232if (!definition.isExtending()
233 || alreadyResolvedDefinitions.contains(definition.getName())) {
234return;
235 }
236237if (log.isDebugEnabled()) {
238 log.debug("Resolve definition for child name='"239 + definition.getName()
240 + "' extends='" + definition.getExtends() + "'.");
241 }
242243// Set as visited to avoid endless recurisvity.244 alreadyResolvedDefinitions.add(definition.getName());
245246// Resolve parent before itself.247 Definition parent = getDefinition(definition.getExtends(),
248 locale);
249if (parent == null) { // error250 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// to do : find better exception257thrownewNoSuchDefinitionException(msg);
258 }
259260 resolveInheritance(parent, locale, alreadyResolvedDefinitions);
261262 definition.inherit(parent);
263 }
264265/***266 * Overloads a child definition with a given parent.267 * All attributes present in child are kept. All missing attributes are268 * copied from the parent.269 * Special attribute 'template','role' and 'extends' are overloaded in child270 * if not defined271 *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
277protectedvoid overload(Definition parent, Definition child) {
278 child.inherit(parent);
279 }
280 }