Nesting templates in Tiles, why are attributes undefined in the included template? - apache

I use Tiles 2 in my web application, and the basic setup I've got in my tiles.xml file is this:
<tiles-definitions>
<definition name="mainLayout" template="/jsp/layout.jsp">
<put-attribute name="header" value=""/>
<put-attribute name="menu" value="/jsp/defaultMenu.jsp" />
<put-attribute name="content" value="" />
<put-attribute name="footer" value="/jsp/footer.jsp" />
</definition>
<definition name="HomePage" extends="mainLayout">
<put-attribute name="content" type="template" value="/jsp/home.jsp"/>
<put-attribute name="homeClass" value="active" />
</definition>
... rest omitted for brevity.
In layout.jsp, which defines the layout, I include the menu in the appropriate place.
<tiles:insertAttribute name="menu" />
So, then inside my menu template, I wanted to use the homeClass attribute defined in tiles.xml.
<tiles:insertAttribute name='homeClass'/>
but I get an error about the homeClass attribute not being defined. If I do an insertAttribute in my layout.jsp, the value is defined properly, but I need it defined in the menu JSP, included from my layout.
So, my question is: How can I have the homeClass attribute passed correctly not just to my layout template, but to the menu template which is included from the layout template?

I believe you could use nested template definitions:
<definition name="mainLayout" template="/jsp/layout.jsp">
<put-attribute name="header" value=""/>
<put-attribute name="menu">
<definition template="/jsp/defaultMenu.jsp">
<put-attribute name="homeClass" value="active"/>
</definition>
</put-attribute>
<put-attribute name="content" value="" />
<put-attribute name="footer" value="/jsp/footer.jsp" />
</definition>

Related

Nested Tiles with Wildcard Support

Tile configuration :
<definition name="*/*/*/*/*/index" extends="defaultLayout.{1}.{2}.{4}">
<put-attribute name="headerLocationPart" >
<definition name="indexLocation" template="/{1}/{2}/mkportal/s/layouts/LocationLayout.jsp">
<put-attribute name="location" value="/{1}/{2}/mkportal/s/location.jsp" />
<put-attribute name="subscriptionBtn" value="/{1}/{2}/mkportal/s/subscriptionBtn.jsp" />
<put-attribute name="indexPromo" value="/{1}/{2}/mkportal/s/indexPromo.jsp" />
</definition>
</put-attribute>
<put-attribute name="body" value="/{1}/{2}/mkportal/s/index.jsp" />
</definition>
When I m going to hit URL from my browser
http://localhost:8080/etisalat/wap/mkportal/s/index.wfv
problem is Nested Definition "indexLocation" does not resolve {1},{2} parameter .
Error is
org.apache.tiles.impl.CannotRenderException: JSPException including path '/{1}/{2}/mkportal/s/layouts/LocationLayout.jsp'.
So I need solution to pass wildcard value to resolve nested tile definition.
Anonymous definitions can't have wildcards because they don't have names.
There is 2 different approaches you might take here
(i don't know which is correct for you because i don't know exactly what you are doing)
1)
You can use cascading="true" attributes instead of the additional definition like…
<definition name="*/*/*/*/*/index" extends="defaultLayout.{1}.{2}.{4}">
<put-attribute name="headerLocationPart" template="/{1}/{2}/mkportal/s/layouts/LocationLayout.jsp"/>
<put-attribute name="location" value="/{1}/{2}/mkportal/s/location.jsp" cascade="true"/>
<put-attribute name="subscriptionBtn" value="/{1}/{2}/mkportal/s/subscriptionBtn.jsp" cascade="true"/>
<put-attribute name="indexPromo" value="/{1}/{2}/mkportal/s/indexPromo.jsp" cascade="true"/>
<put-attribute name="body" value="/{1}/{2}/mkportal/s/index.jsp" />
</definition>
2)
You can use a named definition like…
<definition name="indexLocation.*.*" template="/{1}/{2}/mkportal/s/layouts/LocationLayout.jsp">
<put-attribute name="location" value="/{1}/{2}/mkportal/s/location.jsp" />
<put-attribute name="subscriptionBtn" value="/{1}/{2}/mkportal/s/subscriptionBtn.jsp" />
<put-attribute name="indexPromo" value="/{1}/{2}/mkportal/s/indexPromo.jsp" />
</definition>
<definition name="*/*/*/*/*/index" extends="defaultLayout.{1}.{2}.{4}">
<put-attribute name="headerLocationPart" value="indexLocation.{1}.{2}"/>
<put-attribute name="body" value="/{1}/{2}/mkportal/s/index.jsp" />
</definition>
Reference: http://tiles.apache.org/framework/tutorial/advanced/nesting-extending.html

Extending Tiles with Wildcart Support

Tiles configuration
<definition name="defaultLayout" template="/{1}/{2}/common/{4}/layouts/layout.jsp">
<put-attribute name="header" value="header.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/{1}/{2}/common/s/footer.jsp" />
</definition>
<!-- Default Layout Defination over -->
<definition name="*/*/*/*/*/index" extends="defaultLayout">
<put-attribute name="body" value="/{1}/{2}/common/s/index.jsp" />
Problem is my defaultLayout definition was not replace with define wildcart in child definition.
When I was hit URL from my browser like http://localhost:8080/etisalat/wap/common/b/index.wfv then
Error is
HTTP Status 404 - /{1}/{2}/common/{4}/layouts/layout.jsp
type Status report
message /{1}/{2}/common/{4}/layouts/layout.jsp
description The requested resource (/{1}/{2}/common/{4}/layouts/layout.jsp) is not available.
Apache Tomcat/6.0.32
The wildcard placeholders are not passed on to the inherited definition.
You would need to
<definition name="defaultLayout.*.*.*" template="/{1}/{2}/common/{3}/layouts/layout.jsp">
<put-attribute name="header" value="header.jsp" />
<put-attribute name="body" value="" />
<put-attribute name="footer" value="/{1}/{2}/common/s/footer.jsp" />
</definition>
<definition name="*/*/*/*/*/index" extends="defaultLayout.{1}.{2}.{4}">
<put-attribute name="body" value="/{1}/{2}/common/s/index.jsp" />
...

Why Tiles wildcard definition name could not accept slash(/) character

As we see the Tiles docs said
https://tiles.apache.org/framework/tutorial/advanced/wildcard.html
We can define a wildcard to accept arbitrary name. But if the name includes "/", for example "c4/login". Tiles will throw an exception
org.apache.tiles.definition.NoSuchDefinitionException: c4/login
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:625)
at org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:321)
My definition is below:
<definition name="*" template="/WEB-INF/tiles/basicLayout.jsp">
<put-attribute name="header" value="/WEB-INF/tiles/header.jsp" />
<put-attribute name="content" value="/WEB-INF/pages/{1}.jsp" />
<put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp" />
</definition>
If I change definition to the example below, a name with slash inside is accepted.
<definition name="c4/login" template="/WEB-INF/tiles/basicLayout.jsp">
<put-attribute name="header" value="/WEB-INF/tiles/header.jsp" />
<put-attribute name="content" value="/WEB-INF/pages/c4/login.jsp" />
<put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp" />
</definition>
Please advise. Thanks a lot.
I think I found a more general workaround: use ** as the wildcard:
<definition name="**" template="/WEB-INF/tiles/basicLayout.jsp">
<put-attribute name="header" value="/WEB-INF/tiles/header.jsp" />
<put-attribute name="content" value="/WEB-INF/pages/{1}.jsp" />
<put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp" />
</definition>
I got a workaround solution, use the revised definition below
<definition name="*/*" template="/WEB-INF/tiles/basicLayout.jsp">
<put-attribute name="header" value="/WEB-INF/tiles/header.jsp" />
<put-attribute name="content" value="/WEB-INF/pages/{1}/{2}.jsp" />
<put-attribute name="footer" value="/WEB-INF/tiles/footer.jsp" />
</definition>
Hope this is useful for you.

How do I extend templates in tiles?

I have one master template that has the general site layout frame: "/WEB-INF/jsp/common.jsp"
Then I have another template that will be generally used for another number of pages with similar layout: "/WEB-INF/jsp/features/common.jsp"
The features template basically defines the content of attribute "content" of the "master" template.
I have tried to solve this the following way:
<definition name="product.common" template="/WEB-INF/jsp/common.jsp">
<put-attribute name="content" value="/WEB-INF/jsp/features/common.jsp" />
</definition>
<definition name="features/index" extends="product.common">
<put-attribute name="title" value="Features" />
<put-attribute name="rightContent" value="/WEB-INF/jsp/features/index.jsp" />
</definition>
But this does not work. I get the following error message in my stack trace:
org.apache.tiles.template.NoSuchAttributeException: Attribute 'rightContent' not found.
But the features-template does have the following:
<tiles:insertAttribute name="rightContent" />
Any ideas?
I guess what you need is nesting definitions. You could try something like this.
<definition name="features.common" template="/WEB-INF/jsp/features/common.jsp">
</definition>
<definition name="product.common" template="/WEB-INF/jsp/common.jsp">
<put-attribute name="content" value="features.common" />
</definition>
<definition name="features/index" extends="product.common">
<put-attribute name="title" value="Features" />
<put-attribute name="rightContent" value="/WEB-INF/jsp/features/index.jsp" />
</definition>

Tiles 2, mapping of JSP

I use Tiles 2 with Spring 3.05. I want to map jsp files to controller, e.g.
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.html</url-pattern>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
When I do so, I get "[WARN] org.springframework.web.servlet.PageNotFound [No mapping found for HTTP request with URI [/WEB-INF/*.jsp]" for all tiles.
How can I exclude the tiles (from within WEB-INF) from servlet-mapping? or maybe I can explicitly map those files to tiles servlet?
Instead of doing this in web.xml, you should probably configure it in your context file. The instructions are available in the spring docs.
May this sippet of my spring-context.xml helps you to build your configuration.
It is based on the fact that there are two kind of tiles configuration files:
/WEB-INF/layouts/tiles-layouts.xml contains the tiles layout definitin
/WEB-INF/jsp/controllers/**/views.xml are several files that bind the view and jsp
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="requestContextAttribute" value="requestContext" />
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<!-- Configure Apache Tiles for the view -->
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layouts/tiles-layouts.xml</value>
<value>/WEB-INF/jsp/controllers/**/views.xml</value>
</list>
</property>
</bean>
One of the /WEB-INF/jsp/controllers/**/views.xml files:
<tiles-definitions>
<!-- Pages -->
<definition name="site/list" extends="standard-layout">
<put-attribute name="title" value="List Sites" />
<put-attribute name="body" value="/WEB-INF/jsp/controllers/site/list.jsp" />
</definition>
<definition name="site/show" extends="standard-breadcrumb-layout">
<put-attribute name="title" value="Show Site" />
<put-attribute name="breadcrumbNavigation" value="/WEB-INF/layouts/siteBreadcrumbNavigation.jsp" />
<put-attribute name="body" value="/WEB-INF/jsp/controllers/site/show.jsp" />
</definition>
<definition name="site/create" extends="standard-layout">
<put-attribute name="title" value="Create Site" />
<put-attribute name="body" value="/WEB-INF/jsp/controllers/site/create.jsp" />
</definition>
<definition name="site/update" extends="standard-layout">
<put-attribute name="title" value="Update Site" />
<put-attribute name="body" value="/WEB-INF/jsp/controllers/site/update.jsp" />
</definition>
</tiles-definitions>