blob: 47ccaca36fd24ec69556720c026810977894f19a [file] [log] [blame]
/*
* $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.factory;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tiles.TilesApplicationContext;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.awareness.TilesRequestContextFactoryAware;
import org.apache.tiles.context.ChainedTilesRequestContextFactory;
import org.apache.tiles.context.TilesRequestContextFactory;
import org.apache.tiles.definition.DefinitionsFactory;
import org.apache.tiles.definition.DefinitionsReader;
import org.apache.tiles.definition.LocaleDefinitionsFactory;
import org.apache.tiles.definition.Refreshable;
import org.apache.tiles.definition.UrlDefinitionsFactory;
import org.apache.tiles.definition.dao.BaseLocaleUrlDefinitionDAO;
import org.apache.tiles.definition.dao.DefinitionDAO;
import org.apache.tiles.definition.dao.ResolvingLocaleUrlDefinitionDAO;
import org.apache.tiles.definition.digester.DigesterDefinitionsReader;
import org.apache.tiles.evaluator.AttributeEvaluator;
import org.apache.tiles.evaluator.impl.DirectAttributeEvaluator;
import org.apache.tiles.impl.BasicTilesContainer;
import org.apache.tiles.locale.LocaleResolver;
import org.apache.tiles.locale.impl.DefaultLocaleResolver;
import org.apache.tiles.preparer.BasicPreparerFactory;
import org.apache.tiles.preparer.PreparerFactory;
import org.apache.tiles.reflect.ClassUtil;
import org.apache.tiles.renderer.AttributeRenderer;
import org.apache.tiles.renderer.RendererFactory;
import org.apache.tiles.renderer.impl.BasicRendererFactory;
import org.apache.tiles.renderer.impl.DefinitionAttributeRenderer;
import org.apache.tiles.renderer.impl.StringAttributeRenderer;
import org.apache.tiles.renderer.impl.TemplateAttributeRenderer;
import org.apache.tiles.renderer.impl.UntypedAttributeRenderer;
/**
* Factory that builds a standard Tiles container using only Java code.
*
* @version $Rev$ $Date$
* @since 2.1.0
*/
public class BasicTilesContainerFactory extends AbstractTilesContainerFactory {
/**
* The count of elements in the Tiles context factory chain.
*/
private static final int CONTEXT_FACTORY_CHAIN_COUNT = 3;
/**
* The logging object.
*/
private final Log log = LogFactory.getLog(BasicTilesContainerFactory.class);
/** {@inheritDoc} */
@Override
public TilesContainer createContainer(TilesApplicationContext applicationContext) {
BasicTilesContainer container = instantiateContainer(applicationContext);
TilesRequestContextFactory requestContextFactory =
createRequestContextFactory(applicationContext);
container.setRequestContextFactory(requestContextFactory);
container.setApplicationContext(applicationContext);
LocaleResolver resolver = createLocaleResolver(applicationContext,
requestContextFactory);
container.setDefinitionsFactory(createDefinitionsFactory(applicationContext,
requestContextFactory, resolver));
AttributeEvaluator evaluator = createEvaluator(applicationContext,
requestContextFactory, resolver);
container.setEvaluator(evaluator);
container.setPreparerFactory(createPreparerFactory(applicationContext,
requestContextFactory));
container.setRendererFactory(createRendererFactory(applicationContext,
requestContextFactory, container, evaluator));
return container;
}
/**
* Instantiate the container, without initialization.
*
* @param context The Tiles application context object.
* @return The instantiated container.
* @since 2.1.1
*/
protected BasicTilesContainer instantiateContainer(
TilesApplicationContext context) {
return new BasicTilesContainer();
}
/**
* Create a Tiles request context factory. By default it creates a
* {@link ChainedTilesRequestContextFactory}.
*
* @param context The Tiles application context.
* @return The request context factory.
* @since 2.1.1
*/
protected TilesRequestContextFactory createRequestContextFactory(
TilesApplicationContext context) {
ChainedTilesRequestContextFactory contextFactory = new ChainedTilesRequestContextFactory();
registerChainedRequestContextFactories(contextFactory);
return contextFactory;
}
/**
* Register elements of a chained request context factory.
*
* @param contextFactory The request context factory to use.
* @since 2.1.1
*/
protected void registerChainedRequestContextFactories(
ChainedTilesRequestContextFactory contextFactory) {
List<TilesRequestContextFactory> factories = new ArrayList<TilesRequestContextFactory>(
CONTEXT_FACTORY_CHAIN_COUNT);
registerRequestContextFactory(
"org.apache.tiles.servlet.context.ServletTilesRequestContextFactory",
factories, contextFactory);
registerRequestContextFactory(
"org.apache.tiles.portlet.context.PortletTilesRequestContextFactory",
factories, contextFactory);
registerRequestContextFactory(
"org.apache.tiles.jsp.context.JspTilesRequestContextFactory",
factories, contextFactory);
contextFactory.setFactories(factories);
}
/**
* Registers a {@link TilesRequestContextFactory} specifying its
* classname.
*
* @param className The name of the class to instantiate.
* @param factories The list of factories to add to.
* @param parent The parent {@link TilesRequestContextFactory}. If null
* it won't be considered.
* @since 2.1.1
*/
protected void registerRequestContextFactory(String className,
List<TilesRequestContextFactory> factories,
TilesRequestContextFactory parent) {
TilesRequestContextFactory retValue = null;
try {
Class<? extends TilesRequestContextFactory> clazz = ClassUtil
.getClass(className, TilesRequestContextFactory.class);
retValue = clazz.newInstance();
if (parent != null
&& retValue instanceof TilesRequestContextFactoryAware) {
((TilesRequestContextFactoryAware) retValue)
.setRequestContextFactory(parent);
}
} catch (ClassNotFoundException e) {
if (log.isDebugEnabled()) {
log.debug("Cannot find class '" + className + "', ignoring problem", e);
}
} catch (NotAvailableFeatureException e) {
if (log.isDebugEnabled()) {
log.debug("Not available feature exception during instantiation of class '"
+ className + "', ignoring problem", e);
}
} catch (InstantiationException e) {
throw new TilesContainerFactoryException(
"Cannot instantiate '" + className + "'", e);
} catch (IllegalAccessException e) {
throw new TilesContainerFactoryException(
"Cannot access default constructor '" + className + "'",
e);
}
if (retValue != null) {
factories.add(retValue);
}
}
/**
* Creates the definitions factory. By default it creates a
* {@link UrlDefinitionsFactory} with default dependencies.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param resolver The locale resolver.
*
* @return The definitions factory.
* @since 2.1.1
*/
protected DefinitionsFactory createDefinitionsFactory(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
LocaleResolver resolver) {
LocaleDefinitionsFactory factory = instantiateDefinitionsFactory(
applicationContext, contextFactory, resolver);
factory.setApplicationContext(applicationContext);
factory.setLocaleResolver(resolver);
factory.setDefinitionDAO(createLocaleDefinitionDao(applicationContext,
contextFactory, resolver));
if (factory instanceof Refreshable) {
((Refreshable) factory).refresh();
}
return factory;
}
/**
* Instantiate a new definitions factory based on Locale.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param resolver The locale resolver.
*
* @return The definitions factory.
* @since 2.1.1
*/
protected LocaleDefinitionsFactory instantiateDefinitionsFactory(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
LocaleResolver resolver) {
return new UrlDefinitionsFactory();
}
/**
* Instantiate (and does not initialize) a Locale-based definition DAO.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param resolver The locale resolver.
*
* @return The definition DAO.
* @since 2.1.1
*/
protected BaseLocaleUrlDefinitionDAO instantiateLocaleDefinitionDao(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
LocaleResolver resolver) {
return new ResolvingLocaleUrlDefinitionDAO();
}
/**
* Creates a Locale-based definition DAO.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param resolver The locale resolver.
*
* @return The definition DAO.
* @since 2.1.1
*/
protected DefinitionDAO<Locale> createLocaleDefinitionDao(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
LocaleResolver resolver) {
BaseLocaleUrlDefinitionDAO definitionDao = instantiateLocaleDefinitionDao(
applicationContext, contextFactory, resolver);
definitionDao.setReader(createDefinitionsReader(applicationContext, contextFactory));
definitionDao.setSourceURLs(getSourceURLs(applicationContext, contextFactory));
definitionDao.setApplicationContext(applicationContext);
return definitionDao;
}
/**
* Creates the locale resolver. By default it creates a
* {@link DefaultLocaleResolver}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
*
* @return The locale resolver.
* @since 2.1.1
*/
protected LocaleResolver createLocaleResolver(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory) {
return new DefaultLocaleResolver();
}
/**
* Creates the definitions reader. By default it creates a
* {@link DigesterDefinitionsReader}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
*
* @return The definitions reader.
* @since 2.1.1
*/
protected DefinitionsReader createDefinitionsReader(
TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory) {
return new DigesterDefinitionsReader();
}
/**
* Returns a list containing the URLs to be parsed. By default, it returns a
* list containing the URL point to "/WEB-INF/tiles.xml".
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
*
* @return The source URLs.
* @since 2.1.1
*/
protected List<URL> getSourceURLs(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory) {
List<URL> retValue = new ArrayList<URL>(1);
try {
retValue.add(applicationContext.getResource("/WEB-INF/tiles.xml"));
} catch (IOException e) {
throw new TilesContainerFactoryException(
"Cannot get URL: /WEB-INF/tiles.xml", e);
}
return retValue;
}
/**
* Creates the attribute evaluator to use. By default it returns a {@link DirectAttributeEvaluator}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param resolver The locale resolver.
*
* @return The evaluator.
*/
protected AttributeEvaluator createEvaluator(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
LocaleResolver resolver) {
return new DirectAttributeEvaluator();
}
/**
* Creates the preparer factory to use. By default it returns a
* {@link BasicPreparerFactory}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
*
* @return The preparer factory.
* @since 2.1.1
*/
protected PreparerFactory createPreparerFactory(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory) {
return new BasicPreparerFactory();
}
/**
* Creates a renderer factory. By default it returns a
* {@link BasicRendererFactory}, composed of an
* {@link UntypedAttributeRenderer} as default, and
* {@link StringAttributeRenderer}, {@link TemplateAttributeRenderer} and
* {@link DefinitionAttributeRenderer}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param container The container.
* @param evaluator The evaluator.
*
* @return The renderer factory.
* @since 2.1.1
*/
protected RendererFactory createRendererFactory(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
TilesContainer container, AttributeEvaluator evaluator) {
BasicRendererFactory retValue = new BasicRendererFactory();
retValue.setApplicationContext(applicationContext);
retValue.setRequestContextFactory(contextFactory);
retValue.setContainer(container);
retValue.setEvaluator(evaluator);
retValue.setDefaultRenderer(createDefaultAttributeRenderer(applicationContext,
contextFactory, container, evaluator));
registerAttributeRenderers(retValue, applicationContext, contextFactory,
container, evaluator);
return retValue;
}
/**
* Creates the default attribute renderer. By default it is an
* {@link UntypedAttributeRenderer}.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param container The container.
* @param evaluator The evaluator.
*
* @return The default attribute renderer.
* @since 2.1.1
*/
protected AttributeRenderer createDefaultAttributeRenderer(TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
TilesContainer container,
AttributeEvaluator evaluator) {
UntypedAttributeRenderer retValue = new UntypedAttributeRenderer();
retValue.setApplicationContext(applicationContext);
retValue.setContainer(container);
retValue.setRequestContextFactory(contextFactory);
retValue.setEvaluator(evaluator);
return retValue;
}
/**
* Registers attribute renderers in a {@link BasicRendererFactory}. By
* default, it registers a {@link StringAttributeRenderer}, a
* {@link TemplateAttributeRenderer} and a
* {@link DefinitionAttributeRenderer}.
*
* @param rendererFactory The renderer factory to configure.
* @param applicationContext The Tiles application context.
* @param contextFactory The Tiles context factory.
* @param container The container.
* @param evaluator The evaluator.
* @since 2.1.1
*/
protected void registerAttributeRenderers(
BasicRendererFactory rendererFactory, TilesApplicationContext applicationContext,
TilesRequestContextFactory contextFactory,
TilesContainer container, AttributeEvaluator evaluator) {
StringAttributeRenderer stringRenderer = new StringAttributeRenderer();
stringRenderer.setApplicationContext(applicationContext);
stringRenderer.setRequestContextFactory(contextFactory);
stringRenderer.setEvaluator(evaluator);
rendererFactory.registerRenderer("string", stringRenderer);
TemplateAttributeRenderer templateRenderer = new TemplateAttributeRenderer();
templateRenderer.setApplicationContext(applicationContext);
templateRenderer.setRequestContextFactory(contextFactory);
templateRenderer.setEvaluator(evaluator);
rendererFactory.registerRenderer("template", templateRenderer);
DefinitionAttributeRenderer definitionRenderer = new DefinitionAttributeRenderer();
definitionRenderer.setApplicationContext(applicationContext);
definitionRenderer.setContainer(container);
definitionRenderer.setRequestContextFactory(contextFactory);
definitionRenderer.setEvaluator(evaluator);
rendererFactory.registerRenderer("definition", definitionRenderer);
}
}