1/*2 * $Id: ResolvingLocaleUrlDefinitionDAO.java 823662 2009-10-09 18:48:03Z 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.dao;
2324import java.util.HashSet;
25import java.util.LinkedHashMap;
26import java.util.Locale;
27import java.util.Map;
28import java.util.Set;
2930import org.apache.tiles.Definition;
31import org.apache.tiles.definition.NoSuchDefinitionException;
32import org.slf4j.Logger;
33import org.slf4j.LoggerFactory;
3435/***36 * <p>37 * A definitions DAO (loading URLs and using Locale as a customization key) that38 * 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.046 */47publicclassResolvingLocaleUrlDefinitionDAOextends48CachingLocaleUrlDefinitionDAO {
4950/***51 * The logging object.52 */53privatefinal Logger log = LoggerFactory.getLogger(ResolvingLocaleUrlDefinitionDAO.class);
5455/*** {@inheritDoc} */56 @Override
57protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
58return loadDefinitionsFromURLs(parentLocale);
59 }
6061/*** {@inheritDoc} */62 @Override
63protected 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);
68return retValue;
69 }
7071/*** {@inheritDoc} */72 @Override
73protected Definition getDefinitionFromResolver(String name,
74 Locale customizationKey) {
75 Definition retValue = super.getDefinitionFromResolver(name, customizationKey);
76if (retValue != null && retValue.getExtends() != null) {
77 Definition parent = getDefinition(retValue.getExtends(), customizationKey);
78 retValue.inherit(parent);
79 }
8081return retValue;
82 }
8384/*** {@inheritDoc} */85 @Override
86 @Deprecated
87protectedvoid postDefinitionLoadOperations(
88 Map<String, Definition> localeDefsMap, Locale customizationKey) {
89 resolveInheritances(localeDefsMap, customizationKey);
90super.postDefinitionLoadOperations(localeDefsMap, customizationKey);
91 }
9293/***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.0100 */101protectedvoid resolveInheritances(Map<String, Definition> map, Locale locale) {
102if (map != null) {
103 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
104for (Definition definition : map.values()) {
105 resolveInheritance(definition, map, locale,
106 alreadyResolvedDefinitions);
107 } // end loop108 }
109 }
110111/***112 * Resolve locale-specific inheritance. First, resolve parent's inheritance,113 * then set template to the parent's template. Also copy attributes setted114 * in parent, and not set in child If instance doesn't extend anything, do115 * nothing.116 *117 * @param definition The definition to resolve118 * @param definitions The definitions to take when obtaining a parent119 * definition.120 * @param locale The locale to use.121 * @param alreadyResolvedDefinitions The set of the definitions that have122 * been already resolved.123 * @throws NoSuchDefinitionException If an inheritance can not be solved.124 * @since 2.1.0125 */126protectedvoid resolveInheritance(Definition definition,
127 Map<String, Definition> definitions, Locale locale,
128 Set<String> alreadyResolvedDefinitions) {
129// Already done, or not needed ?130if (!definition.isExtending()
131 || alreadyResolvedDefinitions.contains(definition.getName())) {
132return;
133 }
134135if (log.isDebugEnabled()) {
136 log.debug("Resolve definition for child name='"137 + definition.getName()
138 + "' extends='" + definition.getExtends() + "'.");
139 }
140141// Set as visited to avoid endless recurisvity.142 alreadyResolvedDefinitions.add(definition.getName());
143144// Resolve parent before itself.145 Definition parent = definitions.get(definition.getExtends());
146if (parent == null) { // error147 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 exception153thrownewNoSuchDefinitionException(msg);
154 }
155156 resolveInheritance(parent, definitions, locale,
157 alreadyResolvedDefinitions);
158159 definition.inherit(parent);
160 }
161162/***163 * Copies the definition map to be passed to a higher level of customization164 * key.165 *166 * @param localeDefsMap The map of definition to be copied.167 * @return The copy of the definition map. This particular implementation168 * deep-copies the <code>localeDefsMap</code> into a {@link LinkedHashMap}.169 * @since 2.1.4170 */171 @Override
172protected Map<String, Definition> copyDefinitionMap(
173 Map<String, Definition> localeDefsMap) {
174 Map<String, Definition> retValue = new LinkedHashMap<String, Definition>(
175 localeDefsMap.size());
176177for (Map.Entry<String, Definition> entry : localeDefsMap.entrySet()) {
178 Definition definition = new Definition(entry.getValue());
179 retValue.put(entry.getKey(), definition);
180 }
181182return retValue;
183 }
184 }