Skip to content

SPR-11587: Support multiple TilesContainer per ServletContext #1355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.springframework.web.servlet.view.tiles3;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.jsp.JspFactory;

import org.apache.tiles.TilesContainer;
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.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.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.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer.TilesElActivator;

/**
* @author Torsten Krah
*/
class SpringTilesContainerFactory extends BasicTilesContainerFactory {

private TilesConfigurer tilesConfigurer;

public SpringTilesContainerFactory(TilesConfigurer tilesConfigurer) {
this.tilesConfigurer = tilesConfigurer;
}

@Override
protected TilesContainer createDecoratedContainer(TilesContainer originalContainer, ApplicationContext context) {
return (tilesConfigurer.useMutableTilesContainer ? new CachingTilesContainer(originalContainer) : originalContainer);
}

@Override
protected List<ApplicationResource> getSources(ApplicationContext applicationContext) {
if (tilesConfigurer.definitions != null) {
List<ApplicationResource> result = new LinkedList<>();
for (String definition : tilesConfigurer.definitions) {
Collection<ApplicationResource> 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 (tilesConfigurer.checkRefresh && dao instanceof CachingLocaleUrlDefinitionDAO) {
((CachingLocaleUrlDefinitionDAO) dao).setCheckRefresh(true);
}
return dao;
}

@Override
protected DefinitionsReader createDefinitionsReader(ApplicationContext context) {
DigesterDefinitionsReader reader = (DigesterDefinitionsReader) super.createDefinitionsReader(context);
reader.setValidating(tilesConfigurer.validateDefinitions);
return reader;
}

@Override
protected DefinitionsFactory createDefinitionsFactory(ApplicationContext applicationContext,
LocaleResolver resolver) {

if (tilesConfigurer.definitionsFactoryClass != null) {
DefinitionsFactory factory = BeanUtils.instantiateClass(tilesConfigurer.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 (tilesConfigurer.preparerFactoryClass != null) {
return BeanUtils.instantiateClass(tilesConfigurer.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 (TilesConfigurer.tilesElPresent && JspFactory.getDefaultFactory() != null) {
evaluator = new TilesElActivator().createEvaluator(tilesConfigurer.servletContext);
} else {
evaluator = new DirectAttributeEvaluator();
}
return new BasicAttributeEvaluatorFactory(evaluator);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.springframework.web.servlet.view.tiles3;

import org.apache.tiles.factory.AbstractTilesContainerFactory;
import org.apache.tiles.request.ApplicationContext;
import org.apache.tiles.startup.DefaultTilesInitializer;

/**
* @author Torsten Krah
*/
class SpringTilesInitializer extends DefaultTilesInitializer {

private TilesConfigurer tilesConfigurer;
private final String contextId;

public SpringTilesInitializer(TilesConfigurer tilesConfigurer, final String contextId) {
super();
this.tilesConfigurer = tilesConfigurer;
this.contextId = contextId;
}

@Override
protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) {
return new SpringTilesContainerFactory(this.tilesConfigurer);
}

@Override
protected String getContainerKey(ApplicationContext applicationContext) {
return this.contextId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@
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.BeansException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
Expand Down Expand Up @@ -122,30 +122,31 @@
* @see TilesView
* @see TilesViewResolver
*/
public class TilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean {
public class TilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean, org.springframework.context.ApplicationContextAware {

private static final boolean tilesElPresent =
static final boolean tilesElPresent =
ClassUtils.isPresent("org.apache.tiles.el.ELAttributeEvaluator", TilesConfigurer.class.getClassLoader());


protected final Log logger = LogFactory.getLog(getClass());

private TilesInitializer tilesInitializer;

private String[] definitions;
String[] definitions;

private boolean checkRefresh = false;
boolean checkRefresh = false;

private boolean validateDefinitions = true;
boolean validateDefinitions = true;

private Class<? extends DefinitionsFactory> definitionsFactoryClass;
Class<? extends DefinitionsFactory> definitionsFactoryClass;

private Class<? extends PreparerFactory> preparerFactoryClass;
Class<? extends PreparerFactory> preparerFactoryClass;

private boolean useMutableTilesContainer = false;
boolean useMutableTilesContainer = false;

private ServletContext servletContext;
ServletContext servletContext;

private org.springframework.context.ApplicationContext applicationContext;

/**
* Configure Tiles using a custom TilesInitializer, typically specified as an inner bean.
Expand All @@ -159,7 +160,12 @@ public void setTilesInitializer(TilesInitializer tilesInitializer) {
this.tilesInitializer = tilesInitializer;
}

/**
@Override
public void setApplicationContext(org.springframework.context.ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

/**
* Specify whether to apply Tiles 3.0's "complete-autoload" configuration.
* <p>See {@link org.apache.tiles.extras.complete.CompleteAutoloadTilesContainerFactory}
* for details on the complete-autoload mode.
Expand Down Expand Up @@ -266,7 +272,7 @@ public void setServletContext(ServletContext servletContext) {
public void afterPropertiesSet() throws TilesException {
ApplicationContext preliminaryContext = new SpringWildcardServletTilesApplicationContext(this.servletContext);
if (this.tilesInitializer == null) {
this.tilesInitializer = new SpringTilesInitializer();
this.tilesInitializer = new SpringTilesInitializer(this, applicationContext.getId());
}
this.tilesInitializer.initialize(preliminaryContext);
}
Expand All @@ -281,110 +287,7 @@ public void destroy() throws TilesException {
}


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<ApplicationResource> getSources(ApplicationContext applicationContext) {
if (definitions != null) {
List<ApplicationResource> result = new LinkedList<>();
for (String definition : definitions) {
Collection<ApplicationResource> 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 {
private static class SpringCompleteAutoloadTilesInitializer extends CompleteAutoloadTilesInitializer {

@Override
protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) {
Expand All @@ -402,9 +305,9 @@ protected LocaleResolver createLocaleResolver(ApplicationContext applicationCont
}


private class TilesElActivator {
static class TilesElActivator {

public AttributeEvaluator createEvaluator() {
public AttributeEvaluator createEvaluator(final ServletContext servletContext) {
ELAttributeEvaluator evaluator = new ELAttributeEvaluator();
evaluator.setExpressionFactory(
JspFactory.getDefaultFactory().getJspApplicationContext(servletContext).getExpressionFactory());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ public void afterPropertiesSet() throws Exception {

this.applicationContext = ServletUtil.getApplicationContext(getServletContext());
if (this.renderer == null) {
TilesContainer container = TilesAccess.getContainer(this.applicationContext);
TilesContainer container = TilesAccess.getContainer(this.applicationContext,
getWebApplicationContext().getId());
this.renderer = new DefinitionRenderer(container);
}
}
Expand Down Expand Up @@ -129,6 +130,7 @@ protected void renderMergedOutputModel(Map<String, Object> model, HttpServletReq
}

Request tilesRequest = createTilesRequest(request, response);
TilesAccess.setCurrentContainer(tilesRequest, getWebApplicationContext().getId());
this.renderer.render(getUrl(), tilesRequest);
}

Expand Down
Loading