On Oct 11, 2006, at 6:06 AM, Gregg Leichtman wrote:

I suppose that I could create a different definition like:

<definition name="/mainLayout" path="/tiles/layouts/ siteLayout.jsp">
        <put name="htmlHeader" type="template" value=""/>
<put name="header" type="template" value="/tiles/ headerTile.jsp"/> <put name="rightSideBar" type="template" value="/tiles/ rightSideBarTile.jsp"/> <put name="footer" type="template" value="/tiles/ footerTile.jsp"/>
    </definition>

    <definition name="/htmlHeaderPage" extends="/mainLayout">
<put name="htmlHeader" type="template" value="/tiles/ htmlHeaderTile.jsp"/>
    </definition>

and then use

        <tiles:insert name="/htmlHeaderPage" />

however, I have used the previous method for rendering the "put" described _within_ the definition successfully under Tomcat with shale-1.0.3. This is also described by Dick Starr at:

Antonio was correct, but I think his point somehow got lost. You don't actually need another definition. You need another JSP page. Let's break it down with a simple example:

Suppose you have a definition:

<definition name="foobar" path="/foobar.jsp">
  <put name="header" value="/header.jsp"/>
  <put name="body" value="/body.jsp"/>
  <put name="footer" value="/footer.jsp"/>
</definition>

Then here's foobar.jsp:

<html>
....
<body>
  <tiles:insert name="header"/>
  <tiles:insert name="body"/>
  <tiles:insert name="footer"/>
</body>
</html>


If you just type "/foobar.jsp" into your browser Tiles is going to blow up saying you're trying to insert a definition called "header" which it can't find. It doesn't realize you are already *in* a definition called "foobar" and you're trying to insert an *attribute* called "header" because you never invoked Tiles to get the definition called "foobar". Therefore Tiles thinks you're looking for a definition called "header".

To make the above example work you need an intermediate JSP. Let's call it intermediate.jsp. Here's what it would look like in its entirety:

<%@ taglib uri="http://struts.apache.org/tags-tiles"; prefix="tiles" %>
<tiles:insert name="foobar"/>

Then, instead of typing "/foobar.jsp" in your browser you'd type "/ intermediate.jsp" in your browser. Tiles will go find the definition called "foobar", invoke the foobar.jsp template and process your header, body, and footer.

In JSF, by doing <jsp:forward page="/tiles/layouts/siteLayout.faces"/ > you are calling /siteLayout.jsp directly - as if you simply typed the name of that page in your browser. You are not using Tiles to invoke the template, you are invoking it directly. Using the example above you need to do something like this:

index.jsp:

<jsp:forward page="/intermediate.jsp"/>

intermediate.jsp:

<%@ taglib uri="http://struts.apache.org/tags-tiles"; prefix="tiles" %>
<tiles:insert name="foobar"/>

Or in your case, intermediate.jsp would look like this:

<%@ taglib uri="http://struts.apache.org/tags-tiles"; prefix="tiles" %>
<tiles:insert name="/mainLayout"/>

There are two reasons why this is confusing:

1) Tiles has no controller. You would like to be able to invoke Tiles by simply calling the template page, but you can't. You have to either call an intermediate page that invokes the template using the <tiles:insert> tag to insert the definition. Or you have to use a controller architecture like Struts or JSF that knows how to forward to a Tiles definition. In essence, Struts and JSF are doing the <tiles:insert name="/mainLayout"/> for you in the TielsRequestProcessor and TilesViewHandler respectively. Those components know how to call into Tiles, get a Tiles definition, and process it.

Perhaps you'd like Tiles to have a controller so you could type a URL like "http://mywebapp/mainLayout.tiles"; and a Servlet or something would insert the "mainLayout" definition. But we probably won't do that because Tiles was not meant to be a controller, it was meant to work with other controllers like Struts or JSF. In "standalone" mode it requires an intermediate JSP.

Another option for improvement would be to make Tiles work more like Facelets. Facelets does not require the intermediate page. In Facelets you define your template in a page called / siteLayout.xhtml". Then, if you have a page called "foobar" that extends the template, you directly invoke "/foobar.xhtml" This page then "includes" the template. Tiles requires the intermediate page because it works the other way around. Instead of having pages that include templates, Tiles has definitions that extend templates and include pages. I could give an example but it would just make this post a lot longer.

2) The <tiles:insert> tag is overloaded to mean too many things. <tiles:insert> can be used to insert definitions, attributes, pages, strings, and probably scrambled eggs :-) So when you see a <tiles:insert> tag you need to look further to see what context it is in. Is it trying to insert an attribute? a definition? We're trying to figure out the best way to address this issue. It will probably mean different tags to do different things.

I hope that clears it up.
Thanks,
Greg

Reply via email to