Thursday, August 6, 2009

Tiles Enabling your Struts Project

Tiles is a tag library framework that allows you to create templates for your JSP pages and greatly simplifies the creation of Web front ends and overall maintainability of the view layer in a JEE project.

Tiles is an Apache project, not a struts project, so it can be used with other frameworks as well.  Our project is based on Struts so I’ll limit my post to how we integrate tiles with struts.  If you want more information, I encourage you to check out the project website at the apache foundation where you can download the library, see examples and read documentation to your hearts content.

There are a number of ways to use tiles, we typically use a separate tiles definition xml file to define our screens and use the Tiles Plug-in in the struts-config file.

Struts comes bundled with Tiles, so if you are using struts, you already have what you need to get started.

The Request Processor

Since tiles basically intercepts forward processing in struts, you have to use an extension of the struts request processor class that handles this.  This is easy to do in your struts configuration file:

<?xml version="1.0"?>
<struts-config>
  ...
  <controller 
      processorClass="org.apache.struts.tiles.TilesRequestProcessor"/> 
  ...
</struts-config>


This request processor class deals with parsing the tiles configuration and putting all the pieces together, it intercepts the ‘findForward’ method to see if the forward is a tile definition or if it is just a regular forward.  You can mix tiles with simple forwards in the same implementation of struts, for instance <forward name=”success” path=”/WEB-INF/jsp/SuccessPage.jsp” /> and <forward name=”failure” path=”MyFailureTileDef” /> works just fine.



The Plug-in



The other part to configure in struts-config.xml is the Tiles plug-in which basically allows you to configure tiles for each struts module and initializes the factory for the module.



<?xml version="1.0"?>
<struts-config>
  ...
  <plug-in className="org.apache.struts.tiles.TilesPlugin">
    <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml"/>
  </plug-in>
  ...
</struts-config>




This is where you can set some of the properties of the tiles request processor.  Once you have this in place, you’re all set to begin creating tiles.  In this example, I set the location of the tiles definition file that I want to use in this module.  Since this is the default location, it isn’t required, but in case you want to use a different file, or more likely, multiple definition files, this is how you do it. (comma separate multiple file names).



The Template



Tiles is based on JSP files that are put together at run time.  Note that I said JSP files and not JSPF files.  I had some trouble initially when I tried using tiles, thinking it would be good to call the template files JSP files and the pieces would be JSPF…this didn’t work and switched to using JSP for everything and just organized using folders.



Every tile has a template file, the template then uses the tiles tag library to insert page components using the configuration file which we’ll discuss shortly.  Here is a simple template:



<%@ page %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<html>
<head>
  <title>Simple Tile</title>
</head>
<body>
  Page Header
  <hr />
  <tiles:insert attribute="body" />
  <hr />
  Page Footer
</body>
</html>




as you can see, the template just defines a nice little placeholder for an attribute called ‘body’ which is referenced from the configuration file.



The Configuration File



A simple tiles definition looks something like this:



<?xml version="1.0" encoding="windows-1252" ?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">
<tiles-definitions>
  <definition name="simpletile" page="/WEB-INF/jsp/layout.jsp">
    <put name="body" value="/WEB-INF/jsp/Simple.jsp" />
  </definition>
</tiles-definitions>


This simple definition takes your layout.jsp file and inserts a small Simple.jsp in the body marker.  This file isn’t a complete HTML page, in fact it is likely just a table or a paragraph or something that gets inserted in.  It makes life a whole lot easier when you want to change the navigation menu, or the header or something, you don’t have to change every file…just the layout file.



Where the definitions get interesting though is if you have a hierarchy of page ‘types’ that you want to configure, consider this definition file:



<?xml version="1.0" encoding="windows-1252" ?>
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 1.1//EN" "http://jakarta.apache.org/struts/dtds/tiles-config_1_1.dtd">
<tiles-definitions>
  <definition name="BaseDef" path="/WEB-INF/jsp/layout.jsp">
    <put name="header" value="/WEB-INF/jsp/PageHeader.jsp" />
    <put name="footer" value="/WEB-INF/jsp/PageFooter.jsp" />
    <put name="menu" value="/WEB-INF/jsp/Blank.jsp" />
    <put name="body" value="/WEB-INF/jsp/Blank.jsp" />
  </definition>
  <definition name="ClientPage" extends="BaseDef">
    <put name="menu" value="/WEB-INF/jsp/ClientMenu.jsp" />
  </definition>
  <definition name="SupplierPage" extends="BaseDef">
    <put name="menu" value="/WEB-INF/jsp/SupplierMenu.jsp" />
  </definition>
  <definition name="ClientOrderForm" extends="ClientPage">
    <put name="body" value="/WEB-INF/jsp/OrderForm.jsp" />
  </definition>
</tiles-definitions>


This definition takes the basic page layout that is common to all pages in the “BaseDef” definition and puts in the header and footer components, presumably, the layout.jsp in this definition has an insert for “header”, “footer”, “menu” and “body” such as:



<%@ page %>
<%@ taglib uri="/WEB-INF/struts-tiles.tld" prefix="tiles" %>
<html>
<head>
<title>My WebSite</title>
</head>
<body>
  <tiles:insert attribute="header" />
  <tiles:insert attribute="menu" />
  <tiles:insert attribute="body" />
  <tiles:insert attribute="footer" />
</body>
</html>


Once I have all the high level parts such as the menu, header and footer coded, if I want to add an order form, I simply create a definition that extends the high level page type and then insert my body using the <put> element.



Conclusion



There are lots of ways to use tiles, this is just they way that I have always used it.  It provides me with a mechanism to quickly generate the view layer and easily maintain the look and feel of my entire application by reducing all of the html overhead to one layout page and simple component pages that I can easily change when needed.



Newer versions of tiles are available and all work basically the same way, but I know that some of the architecture has changed over several iterations.  If you know of newer, better ways to use tiles, I invite you to comment and share.

No comments: