All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.web.servlet.view.tiles3.TilesConfigurer Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.web.servlet.view.tiles3;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.el.ArrayELResolver;
import javax.el.BeanELResolver;
import javax.el.CompositeELResolver;
import javax.el.ListELResolver;
import javax.el.MapELResolver;
import javax.el.ResourceBundleELResolver;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tiles.TilesContainer;
import org.apache.tiles.TilesException;
import org.apache.tiles.definition.DefinitionsFactory;
import org.apache.tiles.definition.DefinitionsReader;
import org.apache.tiles.definition.dao.BaseLocaleUrlDefinitionDAO;
import org.apache.tiles.definition.dao.CachingLocaleUrlDefinitionDAO;
import org.apache.tiles.definition.digester.DigesterDefinitionsReader;
import org.apache.tiles.el.ELAttributeEvaluator;
import org.apache.tiles.el.ScopeELResolver;
import org.apache.tiles.el.TilesContextBeanELResolver;
import org.apache.tiles.el.TilesContextELResolver;
import org.apache.tiles.evaluator.AttributeEvaluator;
import org.apache.tiles.evaluator.AttributeEvaluatorFactory;
import org.apache.tiles.evaluator.BasicAttributeEvaluatorFactory;
import org.apache.tiles.evaluator.impl.DirectAttributeEvaluator;
import org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory;
import org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer;
import org.apache.tiles.factory.AbstractTilesContainerFactory;
import org.apache.tiles.factory.BasicTilesContainerFactory;
import org.apache.tiles.impl.mgmt.CachingTilesContainer;
import org.apache.tiles.locale.LocaleResolver;
import org.apache.tiles.preparer.factory.PreparerFactory;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.request.ApplicationContextAware;
import org.apache.tiles.request.ApplicationResource;
import org.apache.tiles.startup.DefaultTilesInitializer;
import org.apache.tiles.startup.TilesInitializer;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.ServletContextAware;

/**
 * Helper class to configure Tiles 3.x for the Spring Framework. See
 * https://tiles.apache.org
 * for more information about Tiles, which basically is a templating mechanism
 * for web applications using JSPs and other template engines.
 *
 * 

The TilesConfigurer simply configures a TilesContainer using a set of files * containing definitions, to be accessed by {@link TilesView} instances. This is a * Spring-based alternative (for usage in Spring configuration) to the Tiles-provided * {@code ServletContextListener} * (e.g. {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesListener} * for usage in {@code web.xml}. * *

TilesViews can be managed by any {@link org.springframework.web.servlet.ViewResolver}. * For simple convention-based view resolution, consider using {@link TilesViewResolver}. * *

A typical TilesConfigurer bean definition looks as follows: * *

 * <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
 *   <property name="definitions">
 *     <list>
 *       <value>/WEB-INF/defs/general.xml</value>
 *       <value>/WEB-INF/defs/widgets.xml</value>
 *       <value>/WEB-INF/defs/administrator.xml</value>
 *       <value>/WEB-INF/defs/customer.xml</value>
 *       <value>/WEB-INF/defs/templates.xml</value>
 *     </list>
 *   </property>
 * </bean>
 * 
* * The values in the list are the actual Tiles XML files containing the definitions. * If the list is not specified, the default is {@code "/WEB-INF/tiles.xml"}. * *

Note that in Tiles 3 an underscore in the name of a file containing Tiles * definitions is used to indicate locale information, for example: * *

 * <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
 *   <property name="definitions">
 *     <list>
 *       <value>/WEB-INF/defs/tiles.xml</value>
 *       <value>/WEB-INF/defs/tiles_fr_FR.xml</value>
 *     </list>
 *   </property>
 * </bean>
 * 
* * @author mick semb wever * @author Rossen Stoyanchev * @author Juergen Hoeller * @since 3.2 * @see TilesView * @see TilesViewResolver */ public class TilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean { private static final boolean tilesElPresent = ClassUtils.isPresent("org.apache.tiles.el.ELAttributeEvaluator", TilesConfigurer.class.getClassLoader()); protected final Log logger = LogFactory.getLog(getClass()); @Nullable private TilesInitializer tilesInitializer; @Nullable private String[] definitions; private boolean checkRefresh = false; private boolean validateDefinitions = true; @Nullable private Class definitionsFactoryClass; @Nullable private Class preparerFactoryClass; private boolean useMutableTilesContainer = false; @Nullable private ServletContext servletContext; /** * Configure Tiles using a custom TilesInitializer, typically specified as an inner bean. *

Default is a variant of {@link org.apache.tiles.startup.DefaultTilesInitializer}, * respecting the "definitions", "preparerFactoryClass" etc properties on this configurer. *

NOTE: Specifying a custom TilesInitializer effectively disables all other bean * properties on this configurer. The entire initialization procedure is then left * to the TilesInitializer as specified. */ public void setTilesInitializer(TilesInitializer tilesInitializer) { this.tilesInitializer = tilesInitializer; } /** * Specify whether to apply Tiles 3.0's "complete-autoload" configuration. *

See {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory} * for details on the complete-autoload mode. *

NOTE: Specifying the complete-autoload mode effectively disables all other bean * properties on this configurer. The entire initialization procedure is then left * to {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer}. * @see org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory * @see org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer */ public void setCompleteAutoload(boolean completeAutoload) { if (completeAutoload) { try { this.tilesInitializer = new SpringCompleteAutoloadTilesInitializer(); } catch (Throwable ex) { throw new IllegalStateException("Tiles-Extras 3.0 not available", ex); } } else { this.tilesInitializer = null; } } /** * Set the Tiles definitions, i.e. the list of files containing the definitions. * Default is "/WEB-INF/tiles.xml". */ public void setDefinitions(String... definitions) { this.definitions = definitions; } /** * Set whether to check Tiles definition files for a refresh at runtime. * Default is "false". */ public void setCheckRefresh(boolean checkRefresh) { this.checkRefresh = checkRefresh; } /** * Set whether to validate the Tiles XML definitions. Default is "true". */ public void setValidateDefinitions(boolean validateDefinitions) { this.validateDefinitions = validateDefinitions; } /** * Set the {@link org.apache.tiles.definition.DefinitionsFactory} implementation to use. * Default is {@link org.apache.tiles.definition.UnresolvingLocaleDefinitionsFactory}, * operating on definition resource URLs. *

Specify a custom DefinitionsFactory, e.g. a UrlDefinitionsFactory subclass, * to customize the creation of Tiles Definition objects. Note that such a * DefinitionsFactory has to be able to handle {@link java.net.URL} source objects, * unless you configure a different TilesContainerFactory. */ public void setDefinitionsFactoryClass(Class definitionsFactoryClass) { this.definitionsFactoryClass = definitionsFactoryClass; } /** * Set the {@link org.apache.tiles.preparer.factory.PreparerFactory} implementation to use. * Default is {@link org.apache.tiles.preparer.factory.BasicPreparerFactory}, creating * shared instances for specified preparer classes. *

Specify {@link SimpleSpringPreparerFactory} to autowire * {@link org.apache.tiles.preparer.ViewPreparer} instances based on specified * preparer classes, applying Spring's container callbacks as well as applying * configured Spring BeanPostProcessors. If Spring's context-wide annotation-config * has been activated, annotations in ViewPreparer classes will be automatically * detected and applied. *

Specify {@link SpringBeanPreparerFactory} to operate on specified preparer * names instead of classes, obtaining the corresponding Spring bean from * the DispatcherServlet's application context. The full bean creation process * will be in the control of the Spring application context in this case, * allowing for the use of scoped beans etc. Note that you need to define one * Spring bean definition per preparer name (as used in your Tiles definitions). * @see SimpleSpringPreparerFactory * @see SpringBeanPreparerFactory */ public void setPreparerFactoryClass(Class preparerFactoryClass) { this.preparerFactoryClass = preparerFactoryClass; } /** * Set whether to use a MutableTilesContainer (typically the CachingTilesContainer * implementation) for this application. Default is "false". * @see org.apache.tiles.mgmt.MutableTilesContainer * @see org.apache.tiles.impl.mgmt.CachingTilesContainer */ public void setUseMutableTilesContainer(boolean useMutableTilesContainer) { this.useMutableTilesContainer = useMutableTilesContainer; } @Override public void setServletContext(ServletContext servletContext) { this.servletContext = servletContext; } /** * Creates and exposes a TilesContainer for this web application, * delegating to the TilesInitializer. * @throws TilesException in case of setup failure */ @Override public void afterPropertiesSet() throws TilesException { Assert.state(this.servletContext != null, "No ServletContext available"); ApplicationContext preliminaryContext = new SpringWildcardServletTilesApplicationContext(this.servletContext); if (this.tilesInitializer == null) { this.tilesInitializer = new SpringTilesInitializer(); } this.tilesInitializer.initialize(preliminaryContext); } /** * Removes the TilesContainer from this web application. * @throws TilesException in case of cleanup failure */ @Override public void destroy() throws TilesException { if (this.tilesInitializer != null) { this.tilesInitializer.destroy(); } } private class SpringTilesInitializer extends DefaultTilesInitializer { @Override protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) { return new SpringTilesContainerFactory(); } } private class SpringTilesContainerFactory extends BasicTilesContainerFactory { @Override protected TilesContainer createDecoratedContainer(TilesContainer originalContainer, ApplicationContext context) { return (useMutableTilesContainer ? new CachingTilesContainer(originalContainer) : originalContainer); } @Override protected List getSources(ApplicationContext applicationContext) { if (definitions != null) { List result = new ArrayList<>(); for (String definition : definitions) { Collection resources = applicationContext.getResources(definition); if (resources != null) { result.addAll(resources); } } return result; } else { return super.getSources(applicationContext); } } @Override protected BaseLocaleUrlDefinitionDAO instantiateLocaleDefinitionDao(ApplicationContext applicationContext, LocaleResolver resolver) { BaseLocaleUrlDefinitionDAO dao = super.instantiateLocaleDefinitionDao(applicationContext, resolver); if (checkRefresh && dao instanceof CachingLocaleUrlDefinitionDAO) { ((CachingLocaleUrlDefinitionDAO) dao).setCheckRefresh(true); } return dao; } @Override protected DefinitionsReader createDefinitionsReader(ApplicationContext context) { DigesterDefinitionsReader reader = (DigesterDefinitionsReader) super.createDefinitionsReader(context); reader.setValidating(validateDefinitions); return reader; } @Override protected DefinitionsFactory createDefinitionsFactory(ApplicationContext applicationContext, LocaleResolver resolver) { if (definitionsFactoryClass != null) { DefinitionsFactory factory = BeanUtils.instantiateClass(definitionsFactoryClass); if (factory instanceof ApplicationContextAware) { ((ApplicationContextAware) factory).setApplicationContext(applicationContext); } BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(factory); if (bw.isWritableProperty("localeResolver")) { bw.setPropertyValue("localeResolver", resolver); } if (bw.isWritableProperty("definitionDAO")) { bw.setPropertyValue("definitionDAO", createLocaleDefinitionDao(applicationContext, resolver)); } return factory; } else { return super.createDefinitionsFactory(applicationContext, resolver); } } @Override protected PreparerFactory createPreparerFactory(ApplicationContext context) { if (preparerFactoryClass != null) { return BeanUtils.instantiateClass(preparerFactoryClass); } else { return super.createPreparerFactory(context); } } @Override protected LocaleResolver createLocaleResolver(ApplicationContext context) { return new SpringLocaleResolver(); } @Override protected AttributeEvaluatorFactory createAttributeEvaluatorFactory(ApplicationContext context, LocaleResolver resolver) { AttributeEvaluator evaluator; if (tilesElPresent && JspFactory.getDefaultFactory() != null) { evaluator = new TilesElActivator().createEvaluator(); } else { evaluator = new DirectAttributeEvaluator(); } return new BasicAttributeEvaluatorFactory(evaluator); } } private static class SpringCompleteAutoloadTilesInitializer extends CompleteAutoloadTilesInitializer { @Override protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) { return new SpringCompleteAutoloadTilesContainerFactory(); } } private static class SpringCompleteAutoloadTilesContainerFactory extends CompleteAutoloadTilesContainerFactory { @Override protected LocaleResolver createLocaleResolver(ApplicationContext applicationContext) { return new SpringLocaleResolver(); } } private class TilesElActivator { public AttributeEvaluator createEvaluator() { ELAttributeEvaluator evaluator = new ELAttributeEvaluator(); evaluator.setExpressionFactory( JspFactory.getDefaultFactory().getJspApplicationContext(servletContext).getExpressionFactory()); evaluator.setResolver(new CompositeELResolverImpl()); return evaluator; } } private static class CompositeELResolverImpl extends CompositeELResolver { public CompositeELResolverImpl() { add(new ScopeELResolver()); add(new TilesContextELResolver(new TilesContextBeanELResolver())); add(new TilesContextBeanELResolver()); add(new ArrayELResolver(false)); add(new ListELResolver(false)); add(new MapELResolver(false)); add(new ResourceBundleELResolver()); add(new BeanELResolver(false)); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy