diff --git a/build.gradle b/build.gradle index 114a7adb62..6d698d7e52 100644 --- a/build.gradle +++ b/build.gradle @@ -655,22 +655,35 @@ project("spring-webmvc") { compile(project(":spring-context")) optional(project(":spring-context-support")) // for Velocity support optional(project(":spring-oxm")) // for MarshallingView - optional("org.apache.tiles:tiles-api:2.1.2") - optional("org.apache.tiles:tiles-core:2.1.2") - optional("org.apache.tiles:tiles-jsp:2.1.2") - optional("org.apache.tiles:tiles-servlet:2.1.2") - optional("net.sourceforge.jexcelapi:jxl:2.6.3") - optional("org.apache.poi:poi:3.9") - optional("com.lowagie:itext:2.1.7") + optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12") + optional("com.fasterxml.jackson.core:jackson-databind:2.3.0") optional("net.sf.jasperreports:jasperreports:5.1.0") { exclude group: "xml-apis", module: "xml-apis" } optional("rome:rome:1.0") + optional("com.lowagie:itext:2.1.7") + optional("net.sourceforge.jexcelapi:jxl:2.6.3") + optional("org.apache.poi:poi:3.9") optional("org.apache.velocity:velocity:1.7") optional("velocity-tools:velocity-tools-view:1.4") optional("org.freemarker:freemarker:2.3.19") - optional("org.codehaus.jackson:jackson-mapper-asl:1.9.12") - optional("com.fasterxml.jackson.core:jackson-databind:2.3.0") + optional("org.apache.tiles:tiles-api:2.2.2") + optional("org.apache.tiles:tiles-core:2.2.2") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + } + optional("org.apache.tiles:tiles-servlet:2.2.2") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + } + optional("org.apache.tiles:tiles-jsp:2.2.2") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + } + optional("org.apache.tiles:tiles-el:2.2.2") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + } + optional("org.apache.tiles:tiles-extras:2.2.2") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + exclude group: "org.springframework", module: "spring-web" + } provided("javax.servlet:jstl:1.2") provided("javax.servlet:javax.servlet-api:3.0.1") provided("javax.servlet.jsp:jsp-api:2.1") @@ -725,13 +738,13 @@ project("spring-webmvc-tiles3") { optional("org.apache.tiles:tiles-jsp:3.0.1") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } + optional("org.apache.tiles:tiles-el:3.0.1") { + exclude group: "org.slf4j", module: "jcl-over-slf4j" + } optional("org.apache.tiles:tiles-extras:3.0.1") { exclude group: "org.slf4j", module: "jcl-over-slf4j" exclude group: "org.springframework", module: "spring-web" } - optional("org.apache.tiles:tiles-el:3.0.1") { - exclude group: "org.slf4j", module: "jcl-over-slf4j" - } provided("javax.servlet:javax.servlet-api:3.0.1") testCompile("org.slf4j:slf4j-jcl:${slf4jVersion}") } diff --git a/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/SpringWildcardServletTilesApplicationContext.java b/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/SpringWildcardServletTilesApplicationContext.java index d03b286724..ad4699657a 100644 --- a/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/SpringWildcardServletTilesApplicationContext.java +++ b/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/SpringWildcardServletTilesApplicationContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.servlet.view.tiles3; import java.io.IOException; @@ -21,14 +22,15 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Locale; - import javax.servlet.ServletContext; import org.apache.tiles.request.ApplicationResource; import org.apache.tiles.request.locale.URLApplicationResource; import org.apache.tiles.request.servlet.ServletApplicationContext; + import org.springframework.core.io.Resource; import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.ObjectUtils; import org.springframework.web.context.support.ServletContextResourcePatternResolver; /** @@ -39,21 +41,15 @@ import org.springframework.web.context.support.ServletContextResourcePatternReso */ public class SpringWildcardServletTilesApplicationContext extends ServletApplicationContext { - /** - * The pattern resolver. - */ - protected ResourcePatternResolver resolver; + private final ResourcePatternResolver resolver; + - /** - * Constructor. - * - * @param servletContext The servlet context. - */ public SpringWildcardServletTilesApplicationContext(ServletContext servletContext) { super(servletContext); - resolver = new ServletContextResourcePatternResolver(servletContext); + this.resolver = new ServletContextResourcePatternResolver(servletContext); } + @Override public ApplicationResource getResource(String localePath) { ApplicationResource retValue = null; @@ -78,20 +74,22 @@ public class SpringWildcardServletTilesApplicationContext extends ServletApplica public Collection getResources(String path) { Resource[] resources; try { - resources = resolver.getResources(path); - } catch (IOException e) { + resources = this.resolver.getResources(path); + } + catch (IOException ex) { return Collections. emptyList(); } Collection resourceList = new ArrayList(); - if (resources != null && resources.length > 0) { - for (int i = 0; i < resources.length; i++) { + if (!ObjectUtils.isEmpty(resources)) { + for (Resource resource : resources) { URL url; try { - url = resources[i].getURL(); + url = resource.getURL(); resourceList.add(new URLApplicationResource(url.toExternalForm(), url)); - } catch (IOException e) { + } + catch (IOException ex) { // shouldn't happen with the kind of resources we're using - throw new IllegalArgumentException("no URL for " + resources[i].toString(), e); + throw new IllegalArgumentException("No URL for " + resource.toString(), ex); } } } diff --git a/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java b/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java index 71ab80a22a..794b1534b7 100644 --- a/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java +++ b/spring-webmvc-tiles3/src/main/java/org/springframework/web/servlet/view/tiles3/TilesConfigurer.java @@ -18,7 +18,6 @@ package org.springframework.web.servlet.view.tiles3; import java.util.LinkedList; import java.util.List; - import javax.el.ArrayELResolver; import javax.el.BeanELResolver; import javax.el.CompositeELResolver; @@ -49,14 +48,15 @@ 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.BasicTilesContainer; 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; @@ -103,13 +103,15 @@ import org.springframework.web.context.ServletContextAware; * @author mick semb wever * @author Rossen Stoyanchev * @since 3.2 + * @see TilesView + * @see TilesViewResolver */ public class TilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean { - private static final boolean tilesElPresent = // requires JSP 2.1 as well as Tiles EL module - ClassUtils.isPresent("javax.servlet.jsp.JspApplicationContext", TilesConfigurer.class.getClassLoader()) && + private static final boolean tilesElPresent = ClassUtils.isPresent("org.apache.tiles.el.ELAttributeEvaluator", TilesConfigurer.class.getClassLoader()); + protected final Log logger = LogFactory.getLog(getClass()); private TilesInitializer tilesInitializer; @@ -128,8 +130,6 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D private ServletContext servletContext; - public TilesConfigurer() { - } /** * Configure Tiles using a custom TilesInitializer, typically specified as an inner bean. @@ -158,10 +158,11 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D try { this.tilesInitializer = new SpringCompleteAutoloadTilesInitializer(); } - catch (Exception ex) { - throw new IllegalStateException("tiles-extras 3.x not available", ex); + catch (Throwable ex) { + throw new IllegalStateException("Tiles-Extras 3.0 not available", ex); } - } else { + } + else { this.tilesInitializer = null; } } @@ -170,7 +171,7 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D * Set the Tiles definitions, i.e. the list of files containing the definitions. * Default is "/WEB-INF/tiles.xml". */ - public void setDefinitions(String[] definitions) { + public void setDefinitions(String... definitions) { this.definitions = definitions; } @@ -318,8 +319,8 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D if (definitionsFactoryClass != null) { DefinitionsFactory factory = BeanUtils.instantiate(definitionsFactoryClass); - if (factory instanceof org.apache.tiles.request.ApplicationContextAware) { - ((org.apache.tiles.request.ApplicationContextAware) factory).setApplicationContext(applicationContext); + if (factory instanceof ApplicationContextAware) { + ((ApplicationContextAware) factory).setApplicationContext(applicationContext); } BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(factory); if (bw.isWritableProperty("localeResolver")) { @@ -352,21 +353,19 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D @Override protected AttributeEvaluatorFactory createAttributeEvaluatorFactory(ApplicationContext context, LocaleResolver resolver) { - return new BasicAttributeEvaluatorFactory(createELEvaluator(context)); - } - - private AttributeEvaluator createELEvaluator(ApplicationContext context) { - if (tilesElPresent) { - AttributeEvaluator evaluator = new TilesElActivator().createEvaluator(); - if (evaluator != null) { - return evaluator; - } + AttributeEvaluator evaluator; + if (tilesElPresent && JspFactory.getDefaultFactory() != null) { + evaluator = new TilesElActivator().createEvaluator(); } - return new DirectAttributeEvaluator(); + else { + evaluator = new DirectAttributeEvaluator(); + } + return new BasicAttributeEvaluatorFactory(evaluator); } } - private class SpringCompleteAutoloadTilesInitializer extends CompleteAutoloadTilesInitializer { + + private static class SpringCompleteAutoloadTilesInitializer extends CompleteAutoloadTilesInitializer { @Override protected AbstractTilesContainerFactory createContainerFactory(ApplicationContext context) { @@ -374,42 +373,29 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D } } - private class SpringCompleteAutoloadTilesContainerFactory extends CompleteAutoloadTilesContainerFactory { + + private static class SpringCompleteAutoloadTilesContainerFactory extends CompleteAutoloadTilesContainerFactory { @Override - public TilesContainer createContainer(ApplicationContext applicationContext) { - CachingTilesContainer cachingContainer = (CachingTilesContainer) super.createContainer(applicationContext); - BasicTilesContainer tilesContainer = (BasicTilesContainer) cachingContainer.getWrappedContainer(); - BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(tilesContainer.getDefinitionsFactory()); - if (bw.isWritableProperty("localeResolver")) { - bw.setPropertyValue("localeResolver", new SpringLocaleResolver()); - } - return tilesContainer; + protected LocaleResolver createLocaleResolver(ApplicationContext applicationContext) { + return new SpringLocaleResolver(); } + } private class TilesElActivator { public AttributeEvaluator createEvaluator() { - try { - // jsp-api-2.1 doesn't default instantiate a factory for us - JspFactory factory = JspFactory.getDefaultFactory(); - if ((factory != null) && (factory.getJspApplicationContext(servletContext).getExpressionFactory() != null)) { - logger.info("Found JSP 2.1 ExpressionFactory"); - ELAttributeEvaluator evaluator = new ELAttributeEvaluator(); - evaluator.setExpressionFactory(factory.getJspApplicationContext(servletContext).getExpressionFactory()); - evaluator.setResolver(new CompositeELResolverImpl()); - return evaluator; - } - } - catch (Throwable ex) { - logger.warn("Could not obtain JSP 2.1 ExpressionFactory", ex); - } - return null; + 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() { @@ -423,4 +409,5 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D add(new BeanELResolver(false)); } } + } diff --git a/spring-webmvc-tiles3/src/test/java/org/springframework/web/servlet/view/tiles3/TilesConfigurerTests.java b/spring-webmvc-tiles3/src/test/java/org/springframework/web/servlet/view/tiles3/TilesConfigurerTests.java index 630e29e030..283d1e6c04 100644 --- a/spring-webmvc-tiles3/src/test/java/org/springframework/web/servlet/view/tiles3/TilesConfigurerTests.java +++ b/spring-webmvc-tiles3/src/test/java/org/springframework/web/servlet/view/tiles3/TilesConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -16,8 +16,6 @@ package org.springframework.web.servlet.view.tiles3; -import static org.junit.Assert.assertNotNull; - import org.apache.tiles.access.TilesAccess; import org.apache.tiles.impl.BasicTilesContainer; import org.apache.tiles.request.ApplicationContext; @@ -25,11 +23,14 @@ import org.apache.tiles.request.Request; import org.apache.tiles.request.servlet.ServletRequest; import org.apache.tiles.request.servlet.ServletUtil; import org.junit.Test; + import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockServletContext; +import static org.junit.Assert.*; + /** * Test fixture for {@link TilesConfigurer}. * @@ -42,7 +43,7 @@ public class TilesConfigurerTests { MockServletContext servletContext = new MockServletContext(); TilesConfigurer tc = new TilesConfigurer(); - tc.setDefinitions(new String[] { "/org/springframework/web/servlet/view/tiles3/tiles-definitions.xml" }); + tc.setDefinitions("/org/springframework/web/servlet/view/tiles3/tiles-definitions.xml"); tc.setCheckRefresh(true); tc.setServletContext(servletContext); tc.afterPropertiesSet(); @@ -57,6 +58,7 @@ public class TilesConfigurerTests { tc.destroy(); } + @Configuration public static class AppConfig { } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java deleted file mode 100644 index 25809bdd10..0000000000 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringTilesApplicationContextFactory.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2002-2012 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 - * - * 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.springframework.web.servlet.view.tiles2; - -import java.io.IOException; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import javax.servlet.ServletContext; - -import org.apache.tiles.Initializable; -import org.apache.tiles.TilesApplicationContext; -import org.apache.tiles.context.AbstractTilesApplicationContextFactory; -import org.apache.tiles.servlet.context.ServletTilesApplicationContext; - -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.web.context.support.ServletContextResourcePatternResolver; - -/** - * Spring-specific subclass of the standard Tiles AbstractTilesApplicationContextFactory, - * passing given properties through as Tiles init-param map. - * - * @author Juergen Hoeller - * @since 3.0 - * @see TilesConfigurer#setTilesProperties - */ -public class SpringTilesApplicationContextFactory extends AbstractTilesApplicationContextFactory - implements Initializable { - - private Map params; - - @Override - public void init(Map params) { - this.params = params; - } - - @Override - public TilesApplicationContext createApplicationContext(Object context) { - return new SpringWildcardServletTilesApplicationContext((ServletContext) context, this.params); - } - - - /** - * Custom subclass of the standard Tiles WildcardServletTilesApplicationContext, - * passing given properties through as Tiles init-param map. - */ - private static class SpringWildcardServletTilesApplicationContext extends ServletTilesApplicationContext { - - private final Map mergedInitParams; - - private final ResourcePatternResolver resolver; - - public SpringWildcardServletTilesApplicationContext(ServletContext servletContext, Map params) { - super(servletContext); - this.mergedInitParams = new LinkedHashMap(); - Enumeration initParamNames = servletContext.getInitParameterNames(); - while (initParamNames.hasMoreElements()) { - String initParamName = initParamNames.nextElement(); - this.mergedInitParams.put(initParamName, servletContext.getInitParameter(initParamName)); - } - if (params != null) { - this.mergedInitParams.putAll(params); - } - this.resolver = new ServletContextResourcePatternResolver(servletContext); - } - - @Override - public Map getInitParams() { - return this.mergedInitParams; - } - - @Override - public URL getResource(String path) throws IOException { - URL retValue = null; - Set urlSet = getResources(path); - if (urlSet != null && !urlSet.isEmpty()) { - retValue = urlSet.iterator().next(); - } - return retValue; - } - - @Override - public Set getResources(String path) throws IOException { - Set urlSet = null; - Resource[] resources = this.resolver.getResources(path); - if (resources != null && resources.length > 0) { - urlSet = new HashSet(); - for (Resource resource : resources) { - urlSet.add(resource.getURL()); - } - } - return urlSet; - } - } - -} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringWildcardServletTilesApplicationContext.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringWildcardServletTilesApplicationContext.java new file mode 100644 index 0000000000..b9c6db99ad --- /dev/null +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/SpringWildcardServletTilesApplicationContext.java @@ -0,0 +1,70 @@ +/* + * Copyright 2002-2013 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 + * + * 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.springframework.web.servlet.view.tiles2; + +import java.io.IOException; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; +import javax.servlet.ServletContext; + +import org.apache.tiles.servlet.context.ServletTilesApplicationContext; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.web.context.support.ServletContextResourcePatternResolver; + +/** + * Spring-specific subclass of the ServletTilesApplicationContext. + * + * @author Juergen Hoeller + * @since 4.0.1 + */ +public class SpringWildcardServletTilesApplicationContext extends ServletTilesApplicationContext { + + private final ResourcePatternResolver resolver; + + + public SpringWildcardServletTilesApplicationContext(ServletContext servletContext) { + super(servletContext); + this.resolver = new ServletContextResourcePatternResolver(servletContext); + } + + + @Override + public URL getResource(String path) throws IOException { + URL retValue = null; + Set urlSet = getResources(path); + if (urlSet != null && !urlSet.isEmpty()) { + retValue = urlSet.iterator().next(); + } + return retValue; + } + + @Override + public Set getResources(String path) throws IOException { + Set urlSet = null; + Resource[] resources = this.resolver.getResources(path); + if (resources != null && resources.length > 0) { + urlSet = new HashSet(); + for (Resource resource : resources) { + urlSet.add(resource.getURL()); + } + } + return urlSet; + } +} diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesConfigurer.java index 7d64ecee9c..8f77131ad8 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -17,25 +17,20 @@ package org.springframework.web.servlet.view.tiles2; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; import java.net.URL; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Properties; 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.TilesApplicationContext; -import org.apache.tiles.TilesContainer; import org.apache.tiles.TilesException; import org.apache.tiles.awareness.TilesApplicationContextAware; -import org.apache.tiles.context.AbstractTilesApplicationContextFactory; -import org.apache.tiles.context.ChainedTilesRequestContextFactory; import org.apache.tiles.context.TilesRequestContextFactory; import org.apache.tiles.definition.DefinitionsFactory; import org.apache.tiles.definition.DefinitionsFactoryException; @@ -44,20 +39,20 @@ import org.apache.tiles.definition.Refreshable; 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.evaluator.AttributeEvaluator; -import org.apache.tiles.evaluator.el.ELAttributeEvaluator; +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.factory.TilesContainerFactory; import org.apache.tiles.impl.BasicTilesContainer; import org.apache.tiles.impl.mgmt.CachingTilesContainer; import org.apache.tiles.locale.LocaleResolver; -import org.apache.tiles.preparer.BasicPreparerFactory; import org.apache.tiles.preparer.PreparerFactory; -import org.apache.tiles.renderer.RendererFactory; -import org.apache.tiles.servlet.context.ServletUtil; -import org.apache.tiles.startup.BasicTilesInitializer; +import org.apache.tiles.startup.AbstractTilesInitializer; import org.apache.tiles.startup.TilesInitializer; import org.springframework.beans.BeanUtils; @@ -66,25 +61,23 @@ import org.springframework.beans.PropertyAccessorFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.ClassUtils; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; import org.springframework.web.context.ServletContextAware; /** * Helper class to configure Tiles 2.x for the Spring Framework. See * http://tiles.apache.org - * for more information about Tiles, which basically is a templating - * mechanism for JSP-based web applications. + * for more information about Tiles, which basically is a templating mechanism + * for web applications using JSPs and other template engines. * - * Note: Spring 3.0 requires Tiles 2.1.2 or above, with explicit support for Tiles 2.2. - * Tiles 2.1's EL support will be activated by default when running on JSP 2.1 or above - * and when the Tiles EL module is present in the classpath. + * Note: Spring 4.0 requires Tiles 2.2.2. Tiles' EL support will + * be activated by default when the Tiles EL module is present in the classpath. * *

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 - * {@link org.apache.tiles.web.startup.TilesListener} (for usage in {@code web.xml}). + * {@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}. @@ -102,9 +95,11 @@ import org.springframework.web.context.ServletContextAware; * <value>/WEB-INF/defs/templates.xml</value> * </list> * </property> - * </bean> + * </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"}. * * @author Juergen Hoeller * @since 2.5 @@ -113,22 +108,14 @@ import org.springframework.web.context.ServletContextAware; */ public class TilesConfigurer implements ServletContextAware, InitializingBean, DisposableBean { - private static final boolean tilesElPresent = // requires JSP 2.1 as well as Tiles EL module - ClassUtils.isPresent( - "javax.servlet.jsp.JspApplicationContext", TilesConfigurer.class.getClassLoader()) && - ClassUtils.isPresent( - "org.apache.tiles.evaluator.el.ELAttributeEvaluator", TilesConfigurer.class.getClassLoader()); - - private static final boolean tiles22Present = ClassUtils.isPresent( - "org.apache.tiles.evaluator.AttributeEvaluatorFactory", TilesConfigurer.class.getClassLoader()); + private 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 boolean overrideLocaleResolver = false; - private String[] definitions; private boolean checkRefresh = false; @@ -141,36 +128,9 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D private boolean useMutableTilesContainer = false; - private final Map tilesPropertyMap = new HashMap(); - private ServletContext servletContext; - public TilesConfigurer() { - // Avoid Tiles 2.1 warn logging when default RequestContextFactory impl class not found - StringBuilder sb = new StringBuilder("org.apache.tiles.servlet.context.ServletTilesRequestContextFactory"); - addClassNameIfPresent(sb, "org.apache.tiles.portlet.context.PortletTilesRequestContextFactory"); - addClassNameIfPresent(sb, "org.apache.tiles.jsp.context.JspTilesRequestContextFactory"); - this.tilesPropertyMap.put(ChainedTilesRequestContextFactory.FACTORY_CLASS_NAMES, sb.toString()); - - // Register further Spring-specific settings which differ from the Tiles defaults - this.tilesPropertyMap.put(AbstractTilesApplicationContextFactory.APPLICATION_CONTEXT_FACTORY_INIT_PARAM, - SpringTilesApplicationContextFactory.class.getName()); - this.tilesPropertyMap.put(DefinitionsFactory.LOCALE_RESOLVER_IMPL_PROPERTY, - SpringLocaleResolver.class.getName()); - this.tilesPropertyMap.put(TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM, - BasicPreparerFactory.class.getName()); - this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM, - Boolean.toString(false)); - } - - private static void addClassNameIfPresent(StringBuilder sb, String className) { - if (ClassUtils.isPresent(className, TilesConfigurer.class.getClassLoader())) { - sb.append(',').append(className); - } - } - - /** * Configure Tiles using a custom TilesInitializer, typically specified as an inner bean. *

Default is a variant of {@link org.apache.tiles.startup.DefaultTilesInitializer}, @@ -196,36 +156,23 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D public void setCompleteAutoload(boolean completeAutoload) { if (completeAutoload) { try { - Class clazz = getClass().getClassLoader().loadClass( - "org.apache.tiles.extras.complete.CompleteAutoloadTilesInitializer"); - this.tilesInitializer = (TilesInitializer) clazz.newInstance(); + this.tilesInitializer = new SpringCompleteAutoloadTilesInitializer(); } - catch (Exception ex) { + catch (Throwable ex) { throw new IllegalStateException("Tiles-Extras 2.2 not available", ex); } } else { this.tilesInitializer = null; } - this.overrideLocaleResolver = completeAutoload; } /** * Set the Tiles definitions, i.e. the list of files containing the definitions. * Default is "/WEB-INF/tiles.xml". */ - public void setDefinitions(String[] definitions) { + public void setDefinitions(String... definitions) { this.definitions = definitions; - if (definitions != null) { - String defs = StringUtils.arrayToCommaDelimitedString(definitions); - if (logger.isInfoEnabled()) { - logger.info("TilesConfigurer: adding definitions [" + defs + "]"); - } - this.tilesPropertyMap.put(DefinitionsFactory.DEFINITIONS_CONFIG, defs); - } - else { - this.tilesPropertyMap.remove(DefinitionsFactory.DEFINITIONS_CONFIG); - } } /** @@ -234,8 +181,6 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ public void setCheckRefresh(boolean checkRefresh) { this.checkRefresh = checkRefresh; - this.tilesPropertyMap.put(CachingLocaleUrlDefinitionDAO.CHECK_REFRESH_INIT_PARAMETER, - Boolean.toString(checkRefresh)); } /** @@ -243,13 +188,11 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ public void setValidateDefinitions(boolean validateDefinitions) { this.validateDefinitions = validateDefinitions; - this.tilesPropertyMap.put(DigesterDefinitionsReader.PARSER_VALIDATE_PARAMETER_NAME, - Boolean.toString(validateDefinitions)); } /** * Set the {@link org.apache.tiles.definition.DefinitionsFactory} implementation to use. - * Default is {@link org.apache.tiles.definition.UrlDefinitionsFactory}, + * 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 @@ -258,8 +201,6 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ public void setDefinitionsFactoryClass(Class definitionsFactoryClass) { this.definitionsFactoryClass = definitionsFactoryClass; - this.tilesPropertyMap.put(TilesContainerFactory.DEFINITIONS_FACTORY_INIT_PARAM, - definitionsFactoryClass.getName()); } /** @@ -283,30 +224,16 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ public void setPreparerFactoryClass(Class preparerFactoryClass) { this.preparerFactoryClass = preparerFactoryClass; - this.tilesPropertyMap.put(TilesContainerFactory.PREPARER_FACTORY_INIT_PARAM, - preparerFactoryClass.getName()); } /** * 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.mgmt.CachingTilesContainer + * @see org.apache.tiles.impl.mgmt.CachingTilesContainer */ public void setUseMutableTilesContainer(boolean useMutableTilesContainer) { this.useMutableTilesContainer = useMutableTilesContainer; - this.tilesPropertyMap.put(TilesContainerFactory.CONTAINER_FACTORY_MUTABLE_INIT_PARAM, - Boolean.toString(useMutableTilesContainer)); - } - - /** - * Set Tiles properties (equivalent to the ServletContext init-params in - * the Tiles documentation), overriding the default settings. - *

NOTE: This property is only effective with Tiles 2.1. - * Tiles 2.2 doesn't support property-based configuration anymore. - */ - public void setTilesProperties(Properties tilesProperties) { - CollectionUtils.mergePropertiesIntoMap(tilesProperties, this.tilesPropertyMap); } @Override @@ -314,64 +241,28 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D this.servletContext = servletContext; } - /** * Creates and exposes a TilesContainer for this web application, * delegating to the TilesInitializer. * @throws TilesException in case of setup failure - * @see #createTilesInitializer() */ @Override public void afterPropertiesSet() throws TilesException { - boolean activateEl = false; - if (tilesElPresent) { - activateEl = new JspExpressionChecker().isExpressionFactoryAvailable(); - if (!this.tilesPropertyMap.containsKey(TilesContainerFactory.ATTRIBUTE_EVALUATOR_INIT_PARAM)) { - this.tilesPropertyMap.put(TilesContainerFactory.ATTRIBUTE_EVALUATOR_INIT_PARAM, activateEl ? - "org.apache.tiles.evaluator.el.ELAttributeEvaluator" : DirectAttributeEvaluator.class.getName()); - } - } - - SpringTilesApplicationContextFactory factory = new SpringTilesApplicationContextFactory(); - factory.init(this.tilesPropertyMap); - TilesApplicationContext preliminaryContext = factory.createApplicationContext(this.servletContext); + TilesApplicationContext preliminaryContext = + new SpringWildcardServletTilesApplicationContext(this.servletContext); if (this.tilesInitializer == null) { this.tilesInitializer = createTilesInitializer(); } this.tilesInitializer.initialize(preliminaryContext); - - if (this.overrideLocaleResolver) { - // We need to do this after initialization simply because we're reusing the - // original CompleteAutoloadTilesInitializer above. We cannot subclass - // CompleteAutoloadTilesInitializer when compiling against Tiles 2.1... - logger.debug("Registering Tiles 2.2 LocaleResolver for complete-autoload setup"); - try { - BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(this.servletContext); - DefinitionsFactory definitionsFactory = container.getDefinitionsFactory(); - Method setter = definitionsFactory.getClass().getMethod("setLocaleResolver", LocaleResolver.class); - setter.invoke(definitionsFactory, new SpringLocaleResolver()); - } - catch (Exception ex) { - throw new IllegalStateException("Cannot override LocaleResolver with SpringLocaleResolver", ex); - } - } - - if (activateEl && this.tilesInitializer instanceof SpringTilesInitializer) { - // Again, we need to do this after initialization since SpringTilesContainerFactory - // cannot override template methods that refer to Tiles 2.2 classes: in this case, - // AttributeEvaluatorFactory as createAttributeEvaluatorFactory return type. - BasicTilesContainer container = (BasicTilesContainer) ServletUtil.getContainer(this.servletContext); - new TilesElActivator().registerEvaluator(container); - } } /** - * Creates a new instance of {@link org.apache.tiles.startup.BasicTilesInitializer}. + * Creates a new instance of {@link SpringTilesInitializer}. *

Override it to use a different initializer. - * @see org.apache.tiles.web.startup.TilesListener#createTilesInitializer() + * @see org.apache.tiles.web.startup.AbstractTilesListener#createTilesInitializer() */ protected TilesInitializer createTilesInitializer() { - return (tiles22Present ? new SpringTilesInitializer() : new BasicTilesInitializer()); + return new SpringTilesInitializer(); } /** @@ -380,18 +271,11 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D */ @Override public void destroy() throws TilesException { - try { - // Tiles 2.2? - ReflectionUtils.invokeMethod(TilesInitializer.class.getMethod("destroy"), this.tilesInitializer); - } - catch (NoSuchMethodException ex) { - // Tiles 2.1... - ServletUtil.setContainer(this.servletContext, null); - } + this.tilesInitializer.destroy(); } - private class SpringTilesInitializer extends BasicTilesInitializer { + private class SpringTilesInitializer extends AbstractTilesInitializer { @Override protected AbstractTilesContainerFactory createContainerFactory(TilesApplicationContext context) { @@ -501,57 +385,48 @@ public class TilesConfigurer implements ServletContextAware, InitializingBean, D TilesRequestContextFactory contextFactory) { return new SpringLocaleResolver(); } - } - - private class JspExpressionChecker { - - public boolean isExpressionFactoryAvailable() { - try { - JspFactory factory = JspFactory.getDefaultFactory(); - if (factory != null && - factory.getJspApplicationContext(servletContext).getExpressionFactory() != null) { - logger.info("Found JSP 2.1 ExpressionFactory"); - return true; - } + @Override + protected AttributeEvaluatorFactory createAttributeEvaluatorFactory(TilesApplicationContext applicationContext, + TilesRequestContextFactory contextFactory, LocaleResolver resolver) { + AttributeEvaluator evaluator; + if (tilesElPresent && JspFactory.getDefaultFactory() != null) { + evaluator = TilesElActivator.createEvaluator(applicationContext); } - catch (Throwable ex) { - logger.warn("Could not obtain JSP 2.1 ExpressionFactory", ex); + else { + evaluator = new DirectAttributeEvaluator(); } - return false; + return new BasicAttributeEvaluatorFactory(evaluator); } } - private class TilesElActivator { + private static class SpringCompleteAutoloadTilesInitializer extends CompleteAutoloadTilesInitializer { - public void registerEvaluator(BasicTilesContainer container) { - logger.debug("Registering Tiles 2.2 AttributeEvaluatorFactory for JSP 2.1"); - try { - ClassLoader cl = TilesElActivator.class.getClassLoader(); - Class aef = cl.loadClass("org.apache.tiles.evaluator.AttributeEvaluatorFactory"); - Class baef = cl.loadClass("org.apache.tiles.evaluator.BasicAttributeEvaluatorFactory"); - Constructor baefCtor = baef.getConstructor(AttributeEvaluator.class); - ELAttributeEvaluator evaluator = new ELAttributeEvaluator(); - evaluator.setApplicationContext(container.getApplicationContext()); - evaluator.init(new HashMap()); - Object baefValue = baefCtor.newInstance(evaluator); - Method setter = container.getClass().getMethod("setAttributeEvaluatorFactory", aef); - setter.invoke(container, baefValue); - Method getRequestContextFactory = BasicTilesContainer.class.getDeclaredMethod("getRequestContextFactory"); - getRequestContextFactory.setAccessible(true); - Method createRendererFactory = BasicTilesContainerFactory.class.getDeclaredMethod("createRendererFactory", - TilesApplicationContext.class, TilesRequestContextFactory.class, TilesContainer.class, aef); - createRendererFactory.setAccessible(true); - BasicTilesContainerFactory tcf = new BasicTilesContainerFactory(); - RendererFactory rendererFactory = (RendererFactory) createRendererFactory.invoke( - tcf, container.getApplicationContext(), getRequestContextFactory.invoke(container), - container, baefValue); - container.setRendererFactory(rendererFactory); - } - catch (Exception ex) { - throw new IllegalStateException("Cannot activate ELAttributeEvaluator", ex); - } + @Override + protected AbstractTilesContainerFactory createContainerFactory(TilesApplicationContext context) { + return new SpringCompleteAutoloadTilesContainerFactory(); + } + } + + + private static class SpringCompleteAutoloadTilesContainerFactory extends CompleteAutoloadTilesContainerFactory { + + @Override + protected LocaleResolver createLocaleResolver(TilesApplicationContext applicationContext, + TilesRequestContextFactory contextFactory) { + return new SpringLocaleResolver(); + } + } + + + private static class TilesElActivator { + + public static AttributeEvaluator createEvaluator(TilesApplicationContext applicationContext) { + ELAttributeEvaluator evaluator = new ELAttributeEvaluator(); + evaluator.setApplicationContext(applicationContext); + evaluator.init(Collections.emptyMap()); + return evaluator; } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesView.java index bfe4f2f7da..0006a488cc 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/tiles2/TilesView.java @@ -18,7 +18,6 @@ package org.springframework.web.servlet.view.tiles2; import java.util.Locale; import java.util.Map; - import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -31,6 +30,7 @@ import org.apache.tiles.impl.BasicTilesContainer; import org.apache.tiles.servlet.context.ServletTilesApplicationContext; import org.apache.tiles.servlet.context.ServletTilesRequestContext; import org.apache.tiles.servlet.context.ServletUtil; + import org.springframework.web.servlet.support.JstlUtils; import org.springframework.web.servlet.support.RequestContext; import org.springframework.web.servlet.view.AbstractUrlBasedView; @@ -41,7 +41,7 @@ import org.springframework.web.servlet.view.AbstractUrlBasedView; * *

This class builds on Tiles2, which requires JSP 2.0. * JSTL support is integrated out of the box due to JSTL's inclusion in JSP 2.0. - * Note: Spring 3.0 requires Tiles 2.1.2 or above. + * Note: Spring 4.0 requires Tiles 2.2.2. * *

Depends on a TilesContainer which must be available in * the ServletContext. This container is typically set up via a diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java index d17372979a..a018949908 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/tiles2/TilesConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -36,7 +36,7 @@ public class TilesConfigurerTests { public void simpleBootstrap() { MockServletContext sc = new MockServletContext(); TilesConfigurer tc = new TilesConfigurer(); - tc.setDefinitions(new String[] {"/org/springframework/web/servlet/view/tiles2/tiles-definitions.xml"}); + tc.setDefinitions("/org/springframework/web/servlet/view/tiles2/tiles-definitions.xml"); tc.setCheckRefresh(true); tc.setServletContext(sc); tc.afterPropertiesSet();