Issue Details (XML | Word | Printable)

Key: SPR-5411
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Juergen Hoeller
Reporter: Simon Barbey
Votes: 11
Watchers: 21
Operations

If you were logged in you would be able to see more operations.
Spring Framework

TilesConfigurer class no longer works with Tiles 2.1.1

Created: 14/Jan/09 10:41 AM   Updated: 26/Nov/09 01:21 PM   Resolved: 08/Jul/09 08:29 AM
Component/s: SpringWEB
Affects Version/s: 2.5.6
Fix Version/s: 3.0 M4

Time Tracking:
Original Estimate: 3d
Original Estimate - 3d
Remaining Estimate: 3d
Remaining Estimate - 3d
Time Spent: Not Specified
Time Spent - Not Specified

File Attachments: 1. Java Source File CustomSpringTilesConfigurer.java (5 kB)
2. Java Source File CustomSpringTilesConfigurer.java (4 kB)
3. Java Source File CustomSpringTilesConfigurer.java (3 kB)
4. Java Source File CustomTilesContainerFactory.java (10 kB)
5. Java Source File CustomTilesContainerFactory.java (8 kB)
6. Java Source File CustomTilesContainerFactory.java (7 kB)
7. Java Source File CustomTilesListener.java (2 kB)
8. Java Source File CustomVelocityTilesView.java (2 kB)
9. Java Source File SpringTilesConfigurer.java (11 kB)
10. Java Source File TilesConfigurer.java (11 kB)

Issue Links:
Related
 
Supersede
 

Virtual Machine: Sun JVM - 1.6
Platform: Resin - 2.1
Spring Forum Reference:: http://forum.springsource.org/showthread.php?t=65907


 Description  « Hide

After upgrading Apache Tiles from version 2.1.0 to 2.1.1, the integration with Spring no longer works.

The class TilesConfigurer fails to initialize properly the Tiles environment, as visible in the stack trace :

java.lang.UnsupportedOperationException: Class org.apache.tiles.web.util.ServletContextAdapter
not recognized a TilesApplicationContext
at org.apache.tiles.factory.TilesContainerFactory.createContainer(TilesContainerFactory.java:219)
at org.springframework.web.servlet.view.tiles2.TilesConfigurer.createTilesContainer(TilesConfigurer.java:214)
at org.springframework.web.servlet.view.tiles2.TilesConfigurer.afterPropertiesSet(TilesConfigurer.java:201)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:473)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:402)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:316)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:282)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:126)
at javax.servlet.GenericServlet.init(GenericServlet.java:69)
at com.caucho.server.dispatch.ServletConfigImpl.createServletImpl(ServletConfigImpl.java:646)
at com.caucho.server.dispatch.ServletConfigImpl.createServlet(ServletConfigImpl.java:587)
at com.caucho.server.dispatch.ServletManager.init(ServletManager.java:154)
at com.caucho.server.webapp.Application.start(Application.java:1654)
at com.caucho.server.deploy.DeployController.startImpl(DeployController.java:621)
at com.caucho.server.deploy.DeployController.restartImpl(DeployController.java:584)
at com.caucho.server.deploy.StartAutoRedeployAutoStrategy.request(StartAutoRedeployAutoStrategy.java:125)
at com.caucho.server.deploy.DeployController.request(DeployController.java:554)
at com.caucho.server.webapp.ApplicationContainer.getApplication(ApplicationContainer.java:885)
at com.caucho.server.webapp.ApplicationContainer.buildInvocation(ApplicationContainer.java:725)
at com.caucho.server.host.Host.buildInvocation(Host.java:459)
at com.caucho.server.host.HostContainer.buildInvocation(HostContainer.java:353)
at com.caucho.server.resin.ServletServer.buildInvocation(ServletServer.java:653)
at com.caucho.server.dispatch.DispatchServer.buildInvocation(DispatchServer.java:198)
at com.caucho.server.hmux.HmuxRequest.handleRequest(HmuxRequest.java:415)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:514)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:520)



Antonio Petrelli added a comment - 16/Jan/09 05:33 AM

FWIW I think that pure java configuration could be used to configure Tiles 2.1.x under a Spring environment. See:
http://tiles.apache.org/framework/tutorial/configuration.html#Pure_Java_configuration
Notice that the docs refer to the 2.1.2-SNAPSHOT version of Tiles.


Richard Jr Barabé added a comment - 13/Mar/09 01:48 PM

Here is a version of the TilesConfigurer class that made rid of some deprecated configuration in the property map. It adds support for using wildcard in definitions ( see http://tiles.apache.org/framework/tutorial/wildcard-configuration.html ), which also enable the definitions files to be in the classpath.

This class also integrates the EL support for spring definition files ( see http://tiles.apache.org/framework/tutorial/advanced/el-support.html ).

usage example :
<bean id="tilesConfigurer" class="com.x.web.tiles2.SpringTilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/*/.tiles-def.xml</value>
<value>classpath:/your/package/directory/anotherTileConfigFile.xml</value>
<value>classpath:*/.tiles-def.xml</value>
</list>
</property>
</bean>

http://richardbarabe.wordpress.com/2009/02/23/apache-tiles-2-integration-with-spring-mvc/


Richard Jr Barabé added a comment - 13/Mar/09 02:03 PM

I'm sorry, my bean configuration didn't use the right class name. Here is the example, corrected :

 
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
    <property name="definitions">
        <list>
            <value>/WEB-INF/**/*.tiles-def.xml</value>
            <value>classpath:/your/package/directory/anotherTileConfigFile.xml</value>
            <value>classpath:**/*.tiles-def.xml</value>
        </list>
    </property>
</bean>

Sorry for the double post. And also,since I didn't know how to use jira properly, it stripped some * in my previous comment.


Keith Donald added a comment - 19/Mar/09 04:33 PM

Another Tiles 2.1 adapted Configurer from the community


Richard Jr Barabé added a comment - 19/Mar/09 05:20 PM

Hello Keith, I downloaded your SpringTilesConfigurer to take a look and, I didn't find how the SpringTilesConfigurer you attached was different from the TilesConfigured I posted before. The only difference I saw was the class name and package, plus two imports, one because you SpringTilesConfigurer is not in the org.springframework.web.servlet.view.tiles2 package, to use the SpringLocaleResolver, and another import of org.springframework.web.servlet.view.tiles2.TilesView, which I didn't manage to find the reference in the class.

Does this class add features, maybe I just didn't see ?


Bjorn Harvold added a comment - 30/Mar/09 06:01 AM

Neither of these solutions will work in an OSGi environment.

[CODE][SIZE="1"]
protected TilesContainer createTilesContainer() throws TilesException { ServletContextAdapter adaptedContext = new ServletContextAdapter(new DelegatingServletConfig()); TilesApplicationContext preliminaryContext = new ServletTilesApplicationContext(adaptedContext); [COLOR="red"]AbstractTilesApplicationContextFactory contextFactory = AbstractTilesApplicationContextFactory.createFactory(preliminaryContext);[/COLOR] <== HERE this.tilesContext = contextFactory.createApplicationContext(adaptedContext); [COLOR="red"]AbstractTilesContainerFactory factory = AbstractTilesContainerFactory.getTilesContainerFactory(this.tilesContext);[/COLOR] <== HERE return factory.createContainer(this.tilesContext); }
[/CODE][/SIZE]

This will fail because Tiles will try to instantiate org.apache.tiles.servlet.context.wildcard.WildcardServletTilesApplicationContextFactory (which is in the tiles-servlet bundle) using org.apache.tiles.reflect.ClassUtil which is in the tiles-api bundle. The tiles-api bundle does not have any import statements to tiles-servlet.


Richard Jr Barabé added a comment - 30/Mar/09 07:39 AM

Hum, I'm not sure to understand, but I'm curious, could you explain a little more ?
Or point me somewhere you think could help me understand and maybe fix the thing ?


Bjorn Harvold added a comment - 31/Mar/09 11:39 PM

I have added an issue with the Tiles team here: https://issues.apache.org/struts/browse/TILES-387


Bjorn Harvold added a comment - 04/Apr/09 01:00 PM

Thanks to Antonio with the Tiles team for pointing me in the right direction. If you use a pure Java configuration it will work in an OSGi environment as well as those pesky class loaders won't come into play.

To summarize:
1. Create a pure java configuration solution that can support Tiles on its own and using the tilesConfigurer. I will attach 3 files all starting with the name Custom, to illustrate my point.
2. If you are just using Tiles, you would only need to indicate the listener class in your deployment descriptor and you are set.
3. If you are using the tilesConfigurer bean, you would only need to indicate the bean in one of Spring's xml files
4. The tilesConfigurer class checks for the existence of a TilesContainer that might have already been initialized by the web.xml listener if the user tries to do both and won't proceed.
5. The tilesConfigurer instantiates the custom tiles container factory and the application context the same way the tiles listener would. My tilesConfigurer is bare boned and only for illustration purposes.
6. The custom container factory supports wildcard paths and tiles defs located in the classpath. If no definitions are injected in the tilesConfigurer bean, the factory will go looking for definition files in some default locations. It too is bare boned and can be worked on.

I created 3 files so people only wishing to use Tiles on its own can do so. The custom container factory can hypothetically be an inner class of tiles configurer.

Cheers
bjorn


Bjorn Harvold added a comment - 04/Apr/09 01:02 PM

Short and sweet way of getting the new tilesConfigurer working using a pure java configuration solution as explained in the Tiles doc and support running within OSGi.


Bjorn Harvold added a comment - 04/Apr/09 01:05 PM

FYI. The custom container factory created above should also support EL definitions if you look at the source. Most of this code was hoisted from Tiles test classes.


Bjorn Harvold added a comment - 17/Apr/09 09:09 PM

Attached updated version of tiles configurer and factory.

The previous files did not completely work as there was a class loading issue in one of the factory methods. I had to override that method and duplicate it in my factory for it to load correctly. There is one outstanding issue with the factory that I am still working on. It works when the tiles defs xml is on the classpath such as "classpath:tiles-defs.xml". However it cannot find the definition file if it's located under WEB-INF as the URL is pointing to "jndi:/localhost//WEB-INF/tiles-defs.xml" and it fails with unknown protocol. It should be pointing to somethng like "file://bundlecontext/78/WEB-INF/tiles-defs.xml" I think, but when you call applicationContext.getResource("/WEB-INF/tiles-defs.xml"), it will create the jndi.... url.


Bjorn Harvold added a comment - 17/Apr/09 09:30 PM

Correction, the url for a resource under WEB-INF should look something like: bundleresource://102/WEB-INF/tiles-defs.xml


Christopher Frost added a comment - 17/Jun/09 01:00 PM

I'm trying this on Spring 3. The TilesConfigurer given above is good but there is another issue to do with the way the provided TilesView works with the latest version of Tiles (I got 2.1.2). I will comment more here once I've done some investigation.


Christopher Frost added a comment - 18/Jun/09 07:49 AM

OK, I've done some propper investigation now. The most recent code in TilesView will never work with Tiles 2.1.2. It has this method,

@Override
	public boolean checkResource() throws Exception {
		TilesContainer container = TilesAccess.getContainer(getServletContext());
		return container.isValidDefinition(getUrl());
	}

The call to isValidDefinition must also pass in a var array of objects. If you pass in HttpServletRequest and HttpServletResponse it will end up with a ServletTilesRequestContextFactory. If you pass in just a PageContext you will get a JspTilesRequestContextFactory. I'm not sure what the difference between these is, when they should be used. In the case above, no RequestContextFactory will be found at all and the page request will fail with an exception that no factory could be found. I have had a quick look at the stuff in the associated fourm thread but had no luck. I don't have the time to dig much further, I believe this is also breaking the new PetClinic sample app that is intended for Spring 3 as it has moved on to Tiles.


Bjorn Harvold added a comment - 18/Jun/09 08:43 AM

Hi Chris

My webapp is running fine with Tiles 2.1.2. Do you encounter this error at runtime or at startup?


Christopher Frost added a comment - 19/Jun/09 03:57 AM

Hi,

I get this at runtime when I make a request that requires tiles to render the view. I'm doing this in a dm Server so it's a slightly different world. I'm going to keep going on it and I'll probably report back after the weekend and let you know what I've found. It would be useful to know if your doing this with Tiles portlet support though?

Thanks, Chris.


Rick Mangi added a comment - 01/Jul/09 11:05 AM

Chris,

Not sure if this is the same issue as you are seeing, but I got this to work (Spring M3 and a build of tiles from the trunk we made a few weeks ago) using the following SpringBeanPreparerFactory. It's not pretty but it did solve the Jsp/Servlet context issue.

public class NickSpringBeanPreparerFactory extends SpringBeanPreparerFactory {

public ViewPreparer getPreparer(String name, TilesRequestContext context)
throws TilesException {
ServletContext c = null;
if (context instanceof ServletTilesRequestContext) { ServletTilesRequestContext strc = (ServletTilesRequestContext) context; c = (ServletContext) strc.getContext(); } else if (context instanceof JspTilesRequestContext) { JspTilesRequestContext j = (JspTilesRequestContext) context; c = j.getPageContext().getServletContext(); }

if (c == null) { throw new TilesException("Could not determine context! " + context.getClass()); }
return super.getPreparer(name, WebApplicationContextUtils
.getWebApplicationContext(c));
}

}

HTH,

Rick


Christopher Frost added a comment - 03/Jul/09 05:37 AM

Hi Rick,

Thanks for the help, I'll be working on this again come Monday so I'll give it a try. I do like they way your resolving the servletContext. Juergen said he would have a fix for the approaching RC1 so I'll see where he is up to as well.

Thanks again, Chris.


Juergen Hoeller added a comment - 06/Jul/09 01:01 PM

Chris, I have a (different) fix for the SpringBeanPreparerFactory issue, and I suppose passing HttpServletRequest and HttpServletResponse references into that isValidDefinition call will work, since we're doing the same for the render call.

However, I'm unclear on which version of TilesConfigurer to use: The one Bjorn submitted is radically different from what we used for Tiles 2.0.5; have you been using that one? Any feedback on whether the first TilesConfigurer patch in this issue can potentially work on OSGi as well?

Juergen


Antonio Petrelli added a comment - 07/Jul/09 02:27 AM

About the OSGi compliance, I wish you to know that a bug in Tiles 2.1.2 has been fixed, and Tiles 2.1.3 is currently under the vote process:
https://issues.apache.org/struts/browse/TILES-404
http://markmail.org/message/gnq4bdf5p5ailvov?q=tiles+2%2E1%2E3


Juergen Hoeller added a comment - 08/Jul/09 08:29 AM

This is resolved in trunk now and should be available in upcoming 3.0 RC1 snapshots.

However, it hasn't been integration-tested yet. Chris, it would be great if you could give this a try with dm Server...

Juergen


Christopher Frost added a comment - 08/Jul/09 08:55 AM

I'll give it a try as soon as a snapshot build goes through, thanks for the work. I've got a copy of the proposed 2.1.3 Tiles so will try it with that as well as the one in our EBR.


Antonio Petrelli added a comment - 10/Jul/09 03:10 AM

Tiles 2.1.3 has been released and declared to be GA.


Eric Rizzo added a comment - 02/Nov/09 10:55 AM

Sorry for being a newb, but it's not clear to me if Tiles 2.1.x can work with Spring 2.5.x without using the patched code attached to this bug? In other words, is there a combination of versions of Tiles 2.1.x and 2.5.x that play nicely together?


Xabier Burgos added a comment - 26/Nov/09 09:40 AM

I know it's a bit late but I took Bjorn's customized configuration classes and modified them to use Tiles 2.2 new interfaces so as to avoid using the deprecated ones and also activated support for velocity (you'll need Velocity 1.6.x and Velocity Tools 2.0.x). So if you want to add Tiles 2.2 and Velocity to your Spring project you just need to add them and configure them with spring.