PDA

View Full Version : Stuck with Tiles


gundakiran
May 21st, 2007, 02:26 PM
I did everything that I can think of, and surfed through all forums but couldn't get on how to solve.. hence I am posting this:

I am using spring portlet MVC and I am trying to use tiles (I m familiar with tiles).

applicationContext.xml

<!-- Tiles Configuration -->
<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles.TilesCo nfigurer">
<property name="factoryClass" value="org.apache.struts.tiles.xmlDefinition.I18nFactoryS et"/>
<property name="definitions">
<list>
<value>/WEB-INF/defs/tiles-defs.xml</value>
</list>
</property>
</bean>

<!-- Default Internal View Resolver -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResou rceViewResolver">
<property name="requestContextAttribute" value="requestContext" />
<property name="viewClass"><value>org.springframework.web.servlet.view.tiles.TilesVi ew</value></property>
</bean>



tiles-defs.xml
<!-- List of Clients Page -->
<definition name="docs.mba.clients.clientList" extends="clients.layout">
<put name="title" value="MBA: Clients"/>
<put name="selected.menu" value="Clients >"/>
<put name="selected.menuItem" value="Client List"/>
<put name="content" value="/jsp/clients/clientList.jsp"/>
</definition>


My Controller:

public ModelAndView handleRenderRequestInternal
(RenderRequest request, RenderResponse response) throws Exception {

//// blah....

return new ModelAndView("docs.mba.clients.clientList","clients",clientList);
}



I included all struts jar files (spring distribution /struts) and it got successfully deployed. But I am getting the following error:


java.lang.ClassCastException: org.apache.struts.tiles.ComponentContext
at org.apache.struts.tiles.ComponentContext.getContex t(ComponentContext.java:187)
at org.springframework.web.servlet.view.tiles.TilesVi ew.getComponentContext(TilesView.java:146)
at org.springframework.web.servlet.view.tiles.TilesVi ew.prepareForRendering(TilesView.java:104)
at org.springframework.web.servlet.view.InternalResou rceView.renderMergedOutputModel(InternalResourceVi ew.java:93)
at org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:250)
at org.springframework.web.servlet.ViewRendererServle t.renderView(ViewRendererServlet.java:111)





I don't understand what I am doing wrong.. Any help is really really appreciated.

Thanks,Kiran

gundakiran
May 22nd, 2007, 12:57 PM
Hello all, I still couldn't figure out the issue.. Does anyone know or has any sample spring web mvc application with tiles ? I spent way too much time on this.. any help is greatly appreciated..

Thanks,Kiran

johnalewis
May 23rd, 2007, 08:17 PM
Well, I'm not much of a Struts Tiles expert and haven't used it with Portlets, but I'll see what I can do to help.

The stack trace indicates the problem is coming from:
org.apache.struts.tiles.ComponentContext.getContex t(ComponentContext.java:187)

From reading the JavaDoc, that's a static method that retrieves the Tiles ComponentContext from the passed-in ServletContext. I imagine that the exception is being thrown because it is failing to find it. Any idea why that would be?

What specific version of Struts are you using? The struts.jar file that comes with Spring is pretty old (looks like version 1.2.9).

gundakiran
May 24th, 2007, 09:58 AM
Thanks for your inputs.

Error is coming from the following TilesView method. If getContext(request) returns null, it doesn't throw the 'ClassCastException'. It was able to get the context, but for some reason it is NOT able to cast. So, I thought it might be due to in-correct version of 'struts.jar' in my container versus my application's struts.jar.

So I made sure that I have only one version of struts.jar. [in my tomcat container this is the only app I have].. I am still getting the same error. Only option is that I will have to build spring.jar from the source code so that I can debug the code...


protected ComponentContext getComponentContext(ComponentDefinition definition, HttpServletRequest request)
throws Exception {
ComponentContext context = ComponentContext.getContext(request);
if (context == null) {
context = new ComponentContext(definition.getAttributes());
ComponentContext.setContext(context, request);
}
else {
context.addMissing(definition.getAttributes());
}
return context;
}

johnalewis
May 25th, 2007, 05:09 PM
Actually, the method that is throwing the exception is the static one:

static public ComponentContext getContext(ServletRequest request) {
if (request.getAttribute("javax.servlet.jsp.jspException") != null) {
return null;
} return (ComponentContext) request.getAttribute(
ComponentConstants.COMPONENT_CONTEXT);
}

I'm looking at that source code from here (http://svn.apache.org/viewvc/struts/struts1/tags/STRUTS_1_2_9/src/share/org/apache/struts/tiles/ComponentContext.java?revision=418534&view=markup).

At debug-time, can you inspect the request for an attribute named "org.apache.struts.taglib.tiles.CompContext" and see what is in there? Looks like that is what is causing the problem. Then we need to track down where that attribute is getting set and why the casting isn't working.

Also, what portal are you using? Your portlet webapp can't really be the only app in Tomcat since it's worthless without a portlet-container in another webapp. Is the portal perhaps using Tiles and already setting this attribute with its own object -- since it would potentially come from a different classloader that could be causing the casting problem.

gundakiran
May 25th, 2007, 06:05 PM
Thanks a lot for your reply.

I am using Liferay portlet container. Yes, Liferay portal is using struts and tiles for its own purpose.

I will debug now and find out the value of 'org.apache.struts.taglib.tiles.CompContext'. I think you are right, it didn't occur to me.. The Liferay portal app might already be setting this attribute. Is there any workaround for this..?

I really appreciate, I was really stuck...

Thanks

johnalewis
May 25th, 2007, 08:16 PM
You could move the struts jar file into shared/lib so that your app and Liferay can get it from the same classloader. That would eliminate the casting problem, but it still won't really work correctly since your tiles configuration wouldn't get used this way.

I think the right thing to do is to clear/restore that attribute for the duration of your Controller with a HandlerInterceptor. In the preHandleRender method of your HandlerInterceptor, you could park the Liferay value in a different attribute or in a ThreadLocal and then null out the attribute. Spring's TilesView will see that the ComponentContext is null and will create one from your ComponentDefinition and put it into the attribute. After your Controller has finished rendering, you can then put the old entry back in the afterRenderCompletion method of your HandlerInterceptor.

It occurs to me this would be a good general HandlerInterceptor to add to Spring that could temporarily "park" a request attribute for the duration of the Handler. I will add a JIRA entry for this.