| /* |
| * $Id$ |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.tiles.definition.dao; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.LinkedHashMap; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import org.apache.tiles.Definition; |
| import org.apache.tiles.definition.DefinitionsFactoryException; |
| import org.apache.tiles.definition.NoSuchDefinitionException; |
| import org.apache.tiles.definition.Refreshable; |
| import org.apache.tiles.definition.pattern.BasicPatternDefinitionResolver; |
| import org.apache.tiles.definition.pattern.PatternDefinitionResolver; |
| import org.apache.tiles.definition.pattern.PatternDefinitionResolverAware; |
| import org.apache.tiles.definition.pattern.wildcard.WildcardDefinitionPatternMatcherFactory; |
| import org.apache.tiles.util.LocaleUtil; |
| |
| /** |
| * <p> |
| * A definitions DAO (loading URLs and using Locale as a customization key) that |
| * caches definitions that have been loaded in a raw way (i.e. with inheritance |
| * that is not resolved). |
| * </p> |
| * <p> |
| * It can check if the URLs change, but by default this feature is turned off. |
| * </p> |
| * |
| * @version $Rev$ $Date$ |
| * @since 2.1.0 |
| */ |
| public class CachingLocaleUrlDefinitionDAO extends BaseLocaleUrlDefinitionDAO |
| implements Refreshable, PatternDefinitionResolverAware<Locale> { |
| |
| /** |
| * Initialization parameter to set whether we want to refresh URLs when they |
| * change. |
| * |
| * @since 2.1.0 |
| */ |
| public static final String CHECK_REFRESH_INIT_PARAMETER = |
| "org.apache.tiles.definition.dao.LocaleUrlDefinitionDAO.CHECK_REFRESH"; |
| |
| /** |
| * The locale-specific set of definitions objects. |
| * |
| * @since 2.1.0 |
| */ |
| protected Map<Locale, Map<String, Definition>> locale2definitionMap; |
| |
| /** |
| * Flag that, when <code>true</code>, enables automatic checking of URLs |
| * changing. |
| * |
| * @since 2.1.0 |
| */ |
| protected boolean checkRefresh = false; |
| |
| /** |
| * Resolves definitions using patterns. |
| * |
| * @since 2.2.0 |
| */ |
| protected PatternDefinitionResolver<Locale> definitionResolver; |
| |
| /** |
| * Constructor. |
| * |
| * @since 2.1.0 |
| */ |
| public CachingLocaleUrlDefinitionDAO() { |
| locale2definitionMap = new HashMap<Locale, Map<String, Definition>>(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void init(Map<String, String> params) { |
| super.init(params); |
| |
| String param = params.get(CHECK_REFRESH_INIT_PARAMETER); |
| checkRefresh = "true".equals(param); |
| WildcardDefinitionPatternMatcherFactory definitionPatternMatcherFactory = |
| new WildcardDefinitionPatternMatcherFactory(); |
| definitionResolver = new BasicPatternDefinitionResolver<Locale>( |
| definitionPatternMatcherFactory, |
| definitionPatternMatcherFactory); |
| } |
| |
| /** {@inheritDoc} */ |
| public void setPatternDefinitionResolver( |
| PatternDefinitionResolver<Locale> definitionResolver) { |
| this.definitionResolver = definitionResolver; |
| } |
| |
| /** {@inheritDoc} */ |
| public Definition getDefinition(String name, Locale customizationKey) { |
| Definition retValue = null; |
| if (customizationKey == null) { |
| customizationKey = LocaleUtil.NULL_LOCALE; |
| } |
| Map<String, Definition> definitions = getDefinitions(customizationKey); |
| if (definitions != null) { |
| retValue = definitions.get(name); |
| |
| if (retValue == null) { |
| retValue = getDefinitionFromResolver(name, customizationKey); |
| |
| if (retValue != null) { |
| try { |
| synchronized (definitions) { |
| definitions.put(name, retValue); |
| } |
| } catch (NoSuchDefinitionException ex) { |
| throw new IllegalStateException( |
| "Unable to resolve wildcard mapping", ex); |
| } |
| } |
| } |
| } |
| |
| return retValue; |
| } |
| |
| /** {@inheritDoc} */ |
| public Map<String, Definition> getDefinitions(Locale customizationKey) { |
| if (customizationKey == null) { |
| customizationKey = LocaleUtil.NULL_LOCALE; |
| } |
| Map<String, Definition> retValue = locale2definitionMap |
| .get(customizationKey); |
| if (retValue == null || (checkRefresh && refreshRequired())) { |
| retValue = checkAndloadDefinitions(customizationKey); |
| } |
| return retValue; |
| } |
| |
| /** {@inheritDoc} */ |
| public synchronized void refresh() { |
| if (refreshRequired()) { |
| locale2definitionMap.clear(); |
| } |
| } |
| |
| /** |
| * Sets the flag to check URL refresh. If not called, the default is |
| * <code>false</code>. |
| * |
| * @param checkRefresh When <code>true</code>, enables automatic checking |
| * of URLs changing. |
| * @since 2.1.0 |
| */ |
| public void setCheckRefresh(boolean checkRefresh) { |
| this.checkRefresh = checkRefresh; |
| } |
| |
| /** |
| * Returns a definition from the definition resolver. |
| * |
| * @param name The name of the definition. |
| * @param customizationKey The customization key to use. |
| * @return The resolved definition. |
| */ |
| protected Definition getDefinitionFromResolver(String name, |
| Locale customizationKey) { |
| return definitionResolver.resolveDefinition(name, |
| customizationKey); |
| } |
| |
| /** |
| * Checks if URLs have changed. If yes, it clears the cache. Then continues |
| * loading definitions. |
| * |
| * @param customizationKey The locale to use when loading URLs. |
| * @return The loaded definitions. |
| * @since 2.1.0 |
| */ |
| protected synchronized Map<String, Definition> checkAndloadDefinitions( |
| Locale customizationKey) { |
| if (checkRefresh && refreshRequired()) { |
| locale2definitionMap.clear(); |
| } |
| loadDefinitions(customizationKey); |
| return locale2definitionMap.get(customizationKey); |
| } |
| |
| /** |
| * Tries to load definitions if necessary. |
| * |
| * @param customizationKey The locale to use when loading URLs. |
| * @return The loaded definitions. |
| * @since 2.1.0 |
| */ |
| protected Map<String, Definition> loadDefinitions(Locale customizationKey) { |
| Map<String, Definition> localeDefsMap = locale2definitionMap |
| .get(customizationKey); |
| if (localeDefsMap != null) { |
| return localeDefsMap; |
| } |
| |
| return loadDefinitionsFromURLs(customizationKey); |
| } |
| |
| /** |
| * Loads definitions from the URLs. |
| * |
| * @param customizationKey The locale to use when loading URLs. |
| * @return The loaded definitions. |
| * @since 2.1.0 |
| */ |
| protected Map<String, Definition> loadDefinitionsFromURLs(Locale customizationKey) { |
| Map<String, Definition> localeDefsMap = loadRawDefinitionsFromURLs(customizationKey); |
| Map<String, Definition> defsMap = definitionResolver |
| .storeDefinitionPatterns(copyDefinitionMap(localeDefsMap), |
| customizationKey); |
| locale2definitionMap.put(customizationKey, defsMap); |
| return localeDefsMap; |
| } |
| |
| /** |
| * Loads the raw definitions from the URLs associated with a locale. |
| * |
| * @param customizationKey The locale to use when loading URLs. |
| * @return The loaded definitions. |
| * @since 2.1.3 |
| */ |
| protected Map<String, Definition> loadRawDefinitionsFromURLs( |
| Locale customizationKey) { |
| Map<String, Definition> localeDefsMap; |
| |
| String postfix = LocaleUtil.calculatePostfix(customizationKey); |
| Locale parentLocale = LocaleUtil.getParentLocale(customizationKey); |
| localeDefsMap = new LinkedHashMap<String, Definition>(); |
| if (parentLocale != null) { |
| Map<String, Definition> parentDefs = loadRawDefinitionsFromURLs(parentLocale); |
| if (parentDefs != null) { |
| localeDefsMap.putAll(parentDefs); |
| } |
| } |
| // For each source, the URL must be loaded. |
| for (URL url : sourceURLs) { |
| String path = url.toExternalForm(); |
| |
| String newPath = LocaleUtil.concatPostfix(path, postfix); |
| try { |
| URL newUrl = new URL(newPath); |
| Map<String, Definition> defsMap = loadDefinitionsFromURL(newUrl); |
| if (defsMap != null) { |
| localeDefsMap.putAll(defsMap); |
| } |
| } catch (MalformedURLException e) { |
| throw new DefinitionsFactoryException("Error parsing URL " |
| + newPath, e); |
| } |
| } |
| return localeDefsMap; |
| } |
| |
| /** |
| * Loads parent definitions, i.e. definitions mapped to a parent locale. |
| * |
| * @param parentLocale The locale to use when loading URLs. |
| * @return The loaded parent definitions. |
| * @since 2.1.0 |
| */ |
| protected Map<String, Definition> loadParentDefinitions(Locale parentLocale) { |
| return loadDefinitions(parentLocale); |
| } |
| |
| /** |
| * Operations to be done after definitions are loaded. |
| * |
| * @param localeDefsMap The loaded definitions. |
| * @param customizationKey The locale to use when loading URLs. |
| * @since 2.1.0 |
| * @deprecated Never used. |
| */ |
| protected void postDefinitionLoadOperations( |
| Map<String, Definition> localeDefsMap, Locale customizationKey) { |
| |
| definitionResolver.storeDefinitionPatterns(localeDefsMap, customizationKey); |
| } |
| |
| /** |
| * Copies the definition map to be passed to a higher level of customization |
| * key. |
| * |
| * @param localeDefsMap The map of definition to be copied. |
| * @return The copy of the definition map. This particular implementation |
| * return the <code>localeDefsMap</code> itself. |
| * @since 2.1.4 |
| */ |
| protected Map<String, Definition> copyDefinitionMap( |
| Map<String, Definition> localeDefsMap) { |
| return localeDefsMap; |
| } |
| } |