Struts in Action: Developing Applications with Tiles
11.3.3 Configuration file declarations
By declaring your Definitions in an XML configuration file, you can make your application load the file at startup and create a "Definition factory" containing your Definitions. Each Definition is identified by the name property that should be unique to all your Definitions. Other components, like ActionForwards, can then refer to the Definition by name.
Declaring Tiles Definitions from a configuration file requires some additional setup to enable support for reading the configuration file when the application initializes. See chapter 4 for more about installing Tiles with Struts 1.1.
The process of using Definitions declared from an XML document is no different than using includes from a JSP file. The main difference is how they are created, how they can be extended, and how the Definitions can be used as Struts ActionForwards.
Creating the configuration
The overall format of the XML configuration is similar to the Struts configuration (since they are both proper XML documents). Unsurprisingly, the syntax used within the XML configuration file is similar to the Tiles <definition> tag, as shown in listing 11.11.
Listing 11.11 The Tiles XML configuration file
<!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="definitionName" page="/layouts/myLayout.jsp"> <put name="title" value="Hello World" /> <put name="header" value="/tiles/header.jsp" /> <put name="footer" value="/tiles/footer.jsp" /> <put name="menu" value="/tiles/menu.jsp" /> <put name="body" value="/tiles/helloBody.jsp" /> </definition> <!-- ... more definitions ... --></tiles-definitions>
An empty Tiles Definitions file is provided with the Blank application on the book's website [Husted].
|NOTE||The name and location of the Tiles Definitions file can be specified in the web application deployment descriptor (web.xml). We recommend creating a conf folder under WEB-INF to store the growing number of configuration files that a Struts application can use.|
A Definition can be declared as a subclass of another Definition. In this case, the new Definition inherits all the attributes and properties of the parent Definition. The property extends is used to indicate the parent Definition:
<definition name="portal.page" extends="portal.masterPage"> <put name="title" value="Tiles 1.1 Portal" /> <put name="body" value="portal.body" /></definition>
In this code segment, we specify a new Definition named portal.page that extends the Definition portal.masterPage. The new Definition inherits all the attributes and properties of its parent. In the preceding fragment, the attributes title and body are overloaded. This inheritance capability allows us to have root Definitions—declaring default attributes—and extended Definitions with specialized attributes (like title and body). If all your Definitions extend one root Definition, changing a value in the root Definition will change that value for all Definitions extended from that root.
Extending is similar to overloading but adds persistence. Overloading describes the process where we specify a Definition and pass it new parameters (or attributes), rather like making a call to a method and passing it parameters. But a <tiles:insert> tag cannot call another <tiles:insert> tag, so the overloaded Definition cannot be referenced and reused. By using the extend property, you are creating a new Definition. This new Definition can then be inserted and overloaded and even extended by another Definition. It is still linked back to its ancestor Definitions through the usual type of inheritance tree, as shown in figure 11.5.
Figure 11.5 Definitions can be extended to create new Definitions.
Extending and overloading Definitions can dramatically reduce the amount of redundant information in your page declarations. Each markup, navigation, and content component in your website schema need be declared only once. The component can then be reused wherever it is needed.
While this is all quite cool, we would still need an extra page to host the Definition. This means to add a new page of content, we need to add the content page and then another page to insert the Definition that specifies the new content. A conventional application will have 60 pages for 60 pages of content. A templated application will use at least 120 pages to cover the same ground. Each of the template pages are smaller and simpler than their conventional counterparts, but file management can be an issue.
A good solution to the page boom is to host the Definitions as Struts ActionForwards.
11.3.4 Using Definitions as ActionForwards
In a Struts application, most pages are not referenced directly but encapsulated by an ActionForward object. The ActionForward is given a unique logical name along with a URI that usually refers to a presentation page. A Struts Action selects and returns an ActionForward to the controller servlet. The ActionServlet then forwards control to the URI specified by the ActionForward's path property. (For more about ActionForwards, see part 1 of this book.)
The Tiles package includes an ActionServlet subclass that also checks the path property against your Definitions. If the Definition id and ActionForward path properties match, then the Definition bean is placed in the request scope, control forwarded to the layout, and your assembled templates are displayed.
Accordingly, you can define ActionForwards that use Definition names instead of URIs:
<action path="/tutorial/testAction2" type="org.apache.struts.example.tiles.tutorial. ForwardExampleAction"> <forward name="failure" path=".forward.example.failure.page"/> <forward name="success" path=".forward.example.success.page"/></action>
Of course, you could also name your Definitions using the traditional slash instead of a dot:
<action path="/tutorial/testAction2" type="org.apache.struts.example.tiles.tutorial. ForwardExampleAction"> <forward name="failure" path="/forward/example/failure.page"/> <forward name="success" path="/forward/example/success.page"/></action>
However, the second naming scheme could be confused with other identifiers related to Actions and page URIs. A good practice is to use dot separators (the first scheme) for the Tile Definitions and the slash separators for ActionForwards. This ensures that the names do not intersect.
The code in your Action is exactly the same as before. If you are switching from presentation page URIs in an ActionForward to a Tiles Definition, most Action classes would not need to be rebuilt. Typically, Action classes ignore the ActionForward path and just deal with the ActionForward by its name.
You can mix and match conventional ActionForwards and Tiles-Definition-ActionForwards in an application. The Tiles ActionServlet deals with each request on its own terms.
When ActionForwards are used this way, the number of template pages in an application drops dramatically. To host 60 pages of content, we just need 60 content pages, plus a small number of utility tiles to provide the standard navigation and layout features. But creating page 61 can mean creating only one more content-only JSP and one more XML Definition, with the latter often being a single line.
Deploying Tiles Definitions as ActionForwards gives you all the power and flexibility of dynamic templates without the usual red tape.
Page 4 of 9