1/*2 * $Id: ResolvingLocaleUrlDefinitionDAO.java 1297705 2012-03-06 20:44:30Z nlebas $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.apache.tiles.request.ApplicationContext;
33import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
3536/**37 * <p>38 * A definitions DAO (loading URLs and using Locale as a customization key) that39 * caches definitions that have been loaded and resolves inheritances.40 * </p>41 * <p>42 * It can check if the URLs change, but by default this feature is turned off.43 * </p>44 *45 * @version $Rev: 1297705 $ $Date: 2012-03-07 07:44:30 +1100 (Wed, 07 Mar 2012) $46 * @since 2.1.047 */48publicclassResolvingLocaleUrlDefinitionDAOextends49CachingLocaleUrlDefinitionDAO {
5051/**52 * The logging object.53 */54privatefinal Logger log = LoggerFactory.getLogger(ResolvingLocaleUrlDefinitionDAO.class);
5556publicResolvingLocaleUrlDefinitionDAO(ApplicationContext applicationContext) {
57super(applicationContext);
58 }
5960/** {@inheritDoc} */61 @Override
62protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) {
63return loadRawDefinitionsFromResources(parentLocale);
64 }
6566 @Override
67protected Map<String, Definition> loadDefinitions(Locale customizationKey) {
68 Map<String, Definition> localeDefsMap = super.loadDefinitions(customizationKey);
69 Map<String, Definition> defsMap = definitionResolver
70 .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap),
71 customizationKey);
72 resolveInheritances(defsMap, customizationKey);
73 locale2definitionMap.put(customizationKey, defsMap);
74return defsMap;
75 }
7677/** {@inheritDoc} */78 @Override
79protectedDefinition getDefinitionFromResolver(String name,
80 Locale customizationKey) {
81Definition retValue = super.getDefinitionFromResolver(name, customizationKey);
82if (retValue != null && retValue.getExtends() != null) {
83Definition parent = getDefinition(retValue.getExtends(), customizationKey);
84 retValue.inherit(parent);
85 }
8687return retValue;
88 }
8990/**91 * Resolve locale-specific extended instances.92 *93 * @param map The definition map containing the definitions to resolve.94 * @param locale The locale to use.95 * @throws NoSuchDefinitionException If a parent definition is not found.96 * @since 2.1.097 */98protectedvoid resolveInheritances(Map<String, Definition> map, Locale locale) {
99if (map != null) {
100 Set<String> alreadyResolvedDefinitions = new HashSet<String>();
101for (Definition definition : map.values()) {
102 resolveInheritance(definition, map, locale,
103 alreadyResolvedDefinitions);
104 } // end loop105 }
106 }
107108/**109 * Resolve locale-specific inheritance. First, resolve parent's inheritance,110 * then set template to the parent's template. Also copy attributes setted111 * in parent, and not set in child If instance doesn't extend anything, do112 * nothing.113 *114 * @param definition The definition to resolve115 * @param definitions The definitions to take when obtaining a parent116 * definition.117 * @param locale The locale to use.118 * @param alreadyResolvedDefinitions The set of the definitions that have119 * been already resolved.120 * @throws NoSuchDefinitionException If an inheritance can not be solved.121 * @since 2.1.0122 */123protectedvoid resolveInheritance(Definition definition,
124 Map<String, Definition> definitions, Locale locale,
125 Set<String> alreadyResolvedDefinitions) {
126// Already done, or not needed ?127if (!definition.isExtending()
128 || alreadyResolvedDefinitions.contains(definition.getName())) {
129return;
130 }
131132 log.debug("Resolve definition for child name='{}' extends='{}.",
133 definition.getName(), definition.getExtends());
134135// Set as visited to avoid endless recursivity.136 alreadyResolvedDefinitions.add(definition.getName());
137138// Resolve parent before itself.139Definition parent = definitions.get(definition.getExtends());
140if (parent == null) { // error141 String msg = "Error while resolving definition inheritance: child '"142 + definition.getName()
143 + "' can't find its ancestor '"144 + definition.getExtends()
145 + "'. Please check your description file.";
146// to do : find better exception147thrownewNoSuchDefinitionException(msg);
148 }
149150 resolveInheritance(parent, definitions, locale,
151 alreadyResolvedDefinitions);
152153 definition.inherit(parent);
154 }
155156/**157 * Copies the definition map to be passed to a higher level of customization158 * key.159 *160 * @param localeDefsMap The map of definition to be copied.161 * @return The copy of the definition map. This particular implementation162 * deep-copies the <code>localeDefsMap</code> into a {@link LinkedHashMap}.163 * @since 2.1.4164 */165 @Override
166protected Map<String, Definition> copyDefinitionMap(
167 Map<String, Definition> localeDefsMap) {
168 Map<String, Definition> retValue = new LinkedHashMap<String, Definition>(
169 localeDefsMap.size());
170171for (Map.Entry<String, Definition> entry : localeDefsMap.entrySet()) {
172Definition definition = newDefinition(entry.getValue());
173 retValue.put(entry.getKey(), definition);
174 }
175176return retValue;
177 }
178 }