app attribute in decorators.xml file

535 views
Skip to first unread message

Caden

unread,
Mar 30, 2012, 12:07:34 PM3/30/12
to SiteMesh 2 Users
I have a question about the solution used here (see the bottom):

http://stackoverflow.com/questions/2885229/java-web-templates-across-multiple-war-files

The answerer uses the skins from another application by having a
decorators.xml like this:

<decorator name="main" page="/decorators/layout.jsp" webapp="skins-
app"> <pattern>/*</pattern> </decorator>

My question is about the webapp attribute. What value should be there
exactly? The context root path? The web-app id from web.xml?

Thanks.

Joe Walnes

unread,
Mar 30, 2012, 12:44:26 PM3/30/12
to sitemes...@googlegroups.com
The webapp attribute is dependent on the Servlet container. For example, on Tomcat, it will typically be the name of the .war file (without the .war suffix).

thanks
-Joe

Caden

unread,
Mar 30, 2012, 12:53:57 PM3/30/12
to SiteMesh 2 Users

Thank you for responding to my question!

I wasn't able to get it to work using the name of the war file, but it
did work if i put in the name of the directory to which the war is
deployed. (They are different for this particular app. I'm not sure
why... historical reasons I guess. :)

Now I am having a different issue. Here is my decorator file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<decorators >
<decorator name="layout" page="/decorators/layout.jsp"
webapp="StyleApp">
<pattern>/*</pattern>
</decorator>
</decorators>

layout.jsp in the providing StyleApp application has the taglib <%@
taglib uri="http://www.opensymphony.com/sitemesh/decorator"
prefix="decorator" %> line and the <decorator:body/> tag. However,
the decorator:body appears to be replaced with nothing in the
consuming application. (It just gets deleted.)

If I go to http://localhost:9080/StyleApp/decorators/layout.jsp and
look at the processed JSP page, the taglib and decorator:body tags
have been removed. I am wondering if the consuming app actually
receives these tags? I suppose it depends on whether it is grabbing
the layout.jsp file before or after it is processed. Does it sound
like I've set this up correctly?

Thanks again,



On Mar 30, 11:44 am, Joe Walnes <j...@walnes.com> wrote:
> The webapp attribute is dependent on the Servlet container. For example, on
> Tomcat, it will typically be the name of the .war file (without the .war
> suffix).
>
> thanks
> -Joe
>
>
>
> On Fri, Mar 30, 2012 at 11:07 AM, Caden <ca...@cadenhowell.com> wrote:
> > I have a question about the solution used here (see the bottom):
>
> >http://stackoverflow.com/questions/2885229/java-web-templates-across-...
>
> > The answerer uses the skins from another application by having a
> > decorators.xml like this:
>
> > <decorator name="main" page="/decorators/layout.jsp" webapp="skins-
> > app">   <pattern>/*</pattern>  </decorator>
>
> > My question is about the webapp attribute.  What value should be there
> > exactly?  The context root path?  The web-app id from web.xml?
>
> > Thanks.- Hide quoted text -
>
> - Show quoted text -

Caden

unread,
Mar 30, 2012, 1:43:22 PM3/30/12
to SiteMesh 2 Users
I should add that when I use layout.jsp, the consuming application
throws this exception:

[3/30/12 12:40:17:194 CDT] 00000022 SystemErr R
java.lang.ClassCastException:
com.opensymphony.sitemesh.compatability.Content2HTMLPage incompatible
with com.opensymphony.module.sitemesh.Page
> > - Show quoted text -- Hide quoted text -

Caden

unread,
Mar 30, 2012, 4:48:54 PM3/30/12
to SiteMesh 2 Users

So, so far, I've set up one web application, StyleApp, with a
layout.jsp file, and another web application which consumes that
layout.jsp with sitemesh 2.4.2. The consumer's decorator file looks
like:

<?xml version="1.0" encoding="ISO-8859-1"?>
<decorators >
<decorator name="layout" page="/decorators/layout.jsp"
webapp="StyleApp">
<pattern>/*</pattern>
</decorator>
</decorators>

I should note as well that we use WebSphere Application Server 6.1
here, and the applications are deployed in separate wars in separate
ears.

When I bring up the consumer page in the web browser I get the
following exception:

[3/30/12 15:22:30:174 CDT] 00000021 ServletWrappe I SRVE0253I:
[DefaultEARNonSecure] [/StyleApp] [/decorators/layout.jsp]: Destroy
successful.
[3/30/12 15:22:30:212 CDT] 00000021 ServletWrappe I SRVE0242I:
[DefaultEARNonSecure] [/StyleApp] [/decorators/layout.jsp]:
Initialization successful.
[3/30/12 15:22:30:219 CDT] 00000021 SystemErr R
java.lang.ClassCastException:
com.opensymphony.sitemesh.compatability.Content2HTMLPage incompatible
with com.opensymphony.module.sitemesh.Page
[3/30/12 15:22:30:219 CDT] 00000021 SystemErr R at
com.opensymphony.module.sitemesh.taglib.AbstractTag.getPage(AbstractTag.java:
64)
[3/30/12 15:22:30:219 CDT] 00000021 SystemErr R at
com.opensymphony.module.sitemesh.taglib.decorator.BodyTag.doEndTag(BodyTag.java:
26)
[3/30/12 15:22:30:219 CDT] 00000021 SystemErr R at
com.ibm._jsp._layout._jspx_meth_decorator_body_0(_layout.java:150)

I downloaded the source code for 2.4.2 from https://java.net/downloads/sitemesh/SiteMesh%202.4.2/
and have been stepping through what happens in the IDE. The exception
occurs here:

com.opensymphony.module.sitemesh.Page.AbstractTag:

protected Page getPage() {
Page p = (Page)pageContext.getAttribute(PAGE,
PageContext.PAGE_SCOPE);
// ^^^ HERE at this cast

if (p == null) {
p = (Page)pageContext.getAttribute(PAGE,
PageContext.REQUEST_SCOPE);
if (p == null) {
pageContext.removeAttribute(PAGE,
PageContext.PAGE_SCOPE);
}
else {
pageContext.setAttribute(PAGE, p,
PageContext.PAGE_SCOPE);
}
pageContext.removeAttribute(PAGE,
PageContext.REQUEST_SCOPE);
}
return p;
}

The PAGE attribute is set earlier here:

com.opensymphony.sitemesh.compatability.OldDecorator2NewDecorator

protected void render(Content content, HttpServletRequest request,
HttpServletResponse response,
ServletContext servletContext,
SiteMeshWebAppContext webAppContext)
throws IOException, ServletException {

request.setAttribute(PAGE, new Content2HTMLPage(content,
request));
// ^^^^ HERE

// see if the URI path (webapp) is set
if (oldDecorator.getURIPath() != null) {
// in a security conscious environment, the servlet
container
// may return null for a given URL
if (servletContext.getContext(oldDecorator.getURIPath()) !
= null) {
servletContext =
servletContext.getContext(oldDecorator.getURIPath());
}
}
// get the dispatcher for the decorator
RequestDispatcher dispatcher =
servletContext.getRequestDispatcher(oldDecorator.getPage());
dispatcher.include(request, response);
^^^^^ include calls the code that eventually calls the
exception code

request.removeAttribute(PAGE);
}

In the comments for this file (OldDecorator2NewDecorator.java) it says
that this class "Adapts a SiteMesh 2 {@link
com.opensymphony.module.sitemesh.Decorator} to a SiteMesh 3 {@link
com.opensymphony.sitemesh.Decorator}." I thought that maybe some new
code had been incorporated, for SiteMesh 3 that had broken it, but I
tried rolling back the library to SiteMesh 2.3 and I got a slightly
different error with a different class name in the same place. (I
neglected to copy the message)

Does anyone have any suggestions about what I could try next? I'm
very interested in this feature, as I like SiteMesh and the ability to
use a single layout from multiple wars would be a big help in our
organization.

Joe Walnes

unread,
Mar 30, 2012, 6:12:24 PM3/30/12
to sitemes...@googlegroups.com
I suspect the issue is to do with sitemesh.jar being loaded in multiple class loaders. If you have 2 identical classes loaded from separate classloaders, the JVM treats them as different and one cannot be cast to the other. Some Servlet engines use separate classloaders for each web-app to ensure they are isolated from each other.

To get around this, there may be a common directory that you can place jars that are loaded as part of the main Servlet engine, instead of the individual web-apps. Place sitemesh.jar in there. In Tomcat there is a common 'lib' directory - maybe there's something similar for WebSphereAS? 

thanks
-Joe

Caden

unread,
Apr 2, 2012, 11:09:55 AM4/2/12
to SiteMesh 2 Users

Hi Joe,

Thanks again for your help. I looked at the classes loaded in each
war (the provider and the consumer) with the Websphere "Class Loader
Viewer" and it looks like sitemesh-2.4.2.jar is only being loaded once
in each .war. Maybe I need to force them to share the same jar? I
have copies loaded it into the WEB-INF/lib directory in each war.

Also, if I roll back the change that points to the separate
application and make it point to a template in the same application,
the error goes away.

I'm also wondering, was I supposed to set up the provider as a non-
Sitemesh enabled site which just delivers the templates through http,
still including the decorator taglib tag and <decorator:body/> tags?
Right now I'm running 2 Sitemesh web applications, both the provider
and the consumer.

Caden
> > com.opensymphony.module.sitemesh.taglib.AbstractTag.getPage(AbstractTag.jav­a:
> > 64)
> > [3/30/12 15:22:30:219 CDT] 00000021 SystemErr     R     at
>
> > com.opensymphony.module.sitemesh.taglib.decorator.BodyTag.doEndTag(BodyTag.­java:
> > organization.- Hide quoted text -

Joe Walnes

unread,
Apr 2, 2012, 12:18:09 PM4/2/12
to sitemes...@googlegroups.com
I believe both sites need access to the jar (because they both need the Content2HTMLPage class.

But they need to be loaded by the same classloader. Even if you place the same .jar file in both WEB-INF/lib folders, they will be different classes as far as Java is concerned. So you need to remove sitemesh.jar from WEB-INF/lib and place it in a parent classloader.

In WSAS, this could be an 'application classloader' - i.e. in a .ear file and shared by multiple.wars. Or in a WebSphere extension or by the main JDK classloader.
There are some docs here:

You may get a better response if you ask the WebSphere community. The specific question you want is 'Where do I place a .jar to ensure that multiple web-apps can load it in the same parent classloader?'.

thanks
-Joe

C. Howell

unread,
Apr 2, 2012, 12:21:00 PM4/2/12
to sitemes...@googlegroups.com
Joe, thanks this is a huge help. I will ask around.  Right now the applications are in separate ears.

C. Howell

unread,
Apr 2, 2012, 12:40:13 PM4/2/12
to sitemes...@googlegroups.com
Joe, you were right on the money.  I moved the jars out of the individual Sitemesh projects and into the directory where they would be loaded by the system classloader.  On my machine, which runs Rational Application Developer 7 and the associated WebSphere AS 6.1, that directory was:

C:\Program Files\IBM\SDP70\runtimes\base_v61\lib

Now it is working across separate wars and ears.  I am going to see if my team is as excited as I am to get this working on a few of our visually mismatched applications.

Thanks again,

Caden

Caden

unread,
Apr 3, 2012, 1:09:09 PM4/3/12
to SiteMesh 2 Users

One more thing, in case anyone tries to get this working on WebSphere
6.1. (I know... probably not that likely :) I did some more reading
and it appears that the preferred way to do this is not to drop the
sitemesh jar into one of the java JRE or WebSphere root lib
directories. The preferred way to share a library across an entire
server or cluster is to create a shared library through the
"Integrated Solutions Console". I used the instructions here and
shared it across the entire server rather than just certain
applications:

http://publib.boulder.ibm.com/infocenter/wasinfo/v6r1/index.jsp?topic=/com.ibm.websphere.ejbfep.multiplatform.doc/info/ae/ae/tcws_sharedlib_app.html
> >>http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/index.jsp?topic...
> >>> > - Show quoted text -- Hide quoted text -
Reply all
Reply to author
Forward
0 new messages