text: , and in many cases, that will be exactly the solution you need for the task at hand. But, as the number of displayed items grow (our collection grows) different problems may arise.
  We might not want to display the whole collection on one page, so we’ll need some kind of achieve the result that we want, but a table with pagination and sorted columns is a very common part of a user interface, and recreating it each time wouldn’t be efficient.
  Thankfully, the Grid component brings with it plenty of ready to use functionality, and it is very easy to deal with. Open the ShowAll.tml template in an IDE of your choice and remove the Loop component and all its content, together with the surrounding table:
  <table width="100%"> <tr t: <td> <a href="#" t: ${celebrity.lastName} </a> </td> <td>${celebrity.firstName}</td> <td> <t:output t: </td> <td>${celebrity.occupation}</td> </tr> </table> In place of this code, add the following line: <t:grid t: character capitalized—much better than the fully capitalized version we had before.
  Here, we see the results of some clever guesses on Tapestry’s side. The only required parameter of the Grid component is source, the same as the required parameter of the Loop component. Through this parameter, Grid receives a number of objects of the same class. It takes the fi rst object of this collection and fi nds out its properties. It tries to create a column for each property, transforming the property’s name for the column’s header (for example, lastName property name gives Last Name column header) and makes some additional sensible adjustments like changing the case of the occupation property values in our example.
  All this is quite impressive, but the table, as it is displayed now, has a number of;
  You can even have two pagers, at the top and at the bottom, by specifying pagerPosition=”both”, or no pagers at all (pagerPosition=”none”). In the latter case however, you will have to provide some custom way of paging through records. The next enhancement will be a link surrounding the celebrity’s last name and linking to the Details page. We’ll be adding an ActionLink and will need to know which Celebrity to link to, so we have the Grid store using the row parameter. This is how the Grid declaration will look:
  <t:grid t:
  As for the page class, we already have the celebrity property in it. It should have been left from our experiments with the Loop component. It will also be used in exactly the same way as with Loop, while iterating through the objects provided by its source parameter, Grid will assign the object that is used to display the current row to the celebrity property.
  The next thing to do is to tell Tapestry that when it comes to the contents of the Last Name column, we do not want Grid to display it in a default way. Instead, we shall provide our own way of displaying the cells of the table that contain the last name. Here is how we do this:
  <t:grid t: <t:parameter <t:pagelink t: ${celebrity.lastName} </t:pagelink> </t:parameter> </t:grid>
  Here, the Grid component contains a special Tapestry element ,:
  Click on the last name of a celebrity, and you should see the Details page with the appropriate details on it. All that is left now is to remove the unwanted Id column and to change the order of the remaining columns. For this, we’ll use two properties of the Grid—remove and reorder. Modify the component’s defi nition in the page template to look like this:
  > efficient way to do this is to use the message catalog, the same one that we used while working with the Select component in the previous chapter. Add the following line to the app.properties file: dateOfBirth-label=Birth Date Run the application, and you will see that the column title has changed appropriately. This way, appending -label to the name of the property displayed
  by the column, you can create the key for a message catalog entry, and thus change the title of any column.
  > as its source, so it invokes the getAllCelebrities method to obtain the content to display. Note however that Grid, after invoking this method, receives a list containing all 15 celebrities in collection, but displays only the first five.
  Click on the pager to view the second page—the same output will appear again. Grid requested for the whole collection again, and this time displayed only the second portion of fi ve celebrities from it. Whenever we view another page, the whole collection is requested from the data source, but only one page of data is displayed. This is not too effi cient but works for our purpose.
  Imagine, however, that our collection contains as many as 10,000 celebrities, and it’s stored in a remote database. Requesting for the whole collection would put a lot of strain on our resources, especially if we are going to have 2,000 pages.
  We need to have the ability to request the celebrities, page-by-page—only the
  First of all, let’s modify the IDataSource interface, adding to it a method for returning a selected range of celebrities:
  public interface IDataSource { List<Celebrity> getAllCelebrities(); Celebrity getCelebrityById(long id); void addCelebrity(Celebrity c); List<Celebrity> getRange(int indexFrom, int indexTo); } Next, we need to implement this method in the available implementation of this interface. Add the following method to the MockDataSource class: public List<Celebrity> getRange(int indexFrom, int indexTo) { List<Celebrity> result = new ArrayList<Celebrity>(); for (int i = indexFrom; i <= indexTo; i++) { result.add(celebrities.get(i)); } return result; }
  The code is quite simple, we are returning a subset of the existing collection starting from one index value and ending with the other. In a real-life implementation, we would probably check whether indexTo is bigger than indexFrom, but here, let’s keep things simple.
  Here is one possible implementation of GridDataSource. There are plenty of output statements in it that do not do anything very useful, but they will allow us to witness the inner life of Grid and GridDataSet in tandem. Have a look at the code, and then we’ll walk through it step-by-step:
  package com.packtpub.celebrities.util; import com.packtpub.celebrities.data.IDataSource; import com.packtpub.celebrities.model.Celebrity; import java.util.List; import org.apache.tapestry.beaneditor.PropertyModel; import org.apache.tapestry.grid.GridDataSource; public class CelebritySource implements GridDataSource { private IDataSource dataSource; private List<Celebrity> selection; private int indexFrom; public CelebritySource(IDataSource ds) { this.dataSource = ds; } public int getAvailableRows() { return dataSource.getAllCelebrities().size(); } public void prepare(int indexFrom, int indexTo, PropertyModel propertyModel, boolean ascending) { System.out.println("Preparing selection."); System.out.println("Index from " + indexFrom + " to " + indexTo); String propertyName = propertyModel == null? null : propertyModel.getPropertyName(); System.out.println("Property name is: " + propertyName); System.out.println("Sorting order ascending: " + ascending); selection = dataSource.getRange(indexFrom, indexTo); this.indexFrom = indexFrom; } public Object getRowValue(int i) { System.out.println("Getting value for row " + i); return selection.get(i - this.indexFrom); } public Class getRowType() { return Celebrity.class; } }
  First of all, when creating an instance of CelebritySource, we are passing an implementation of IDataSource that will imitate an actual data source to its constructor. In real life this could be some Data Access Object. The GridDataSource interface that we implemented contains four methods: getAvailableRows(), prepare(), getRowValue(), and getRowType(). The simplest of them is getRowType(). It simply reports which type of objects are served by this implementation of GridDataSource.
  The getAvailableRows method returns the total number of entities available in the data source (this is needed to know the number of pages and to construct the pager properly). In our case, we are simply returning the size of a collection. In real life, this method could contain a request to the database that would return the total available number of records in a search result, without actually returning all those records. If you insert an output statement into this method, you will notice that it is invoked by Grid several times, even while a single page of the table is displayed. You will not want to call the database that many times, so you will need to include some logic to
  cache the result returned by this method, and update it only when necessary.
  But, again, we are looking at the principles here, so let’s keep everything simple. The prepare method does the main job of requesting the database and obtaining a subset of entities from it to be displayed by the current page of the table. The subset is limited by the fi rst two parameters—indexFrom and indexTo, which are the indexes of the fi rst and the last entities to be returned.
  They might be used in a SELECT statement which would command the database to select all the entities and then limit the selection in one way or another, depending on the SQL dialect. The third parameter of this method, propertyModel, is used the order in which the results should be sorted when speaking to the database, but we are just outputting its value.
  The last of the four methods, getRowValue(), returns the entity requested by Grid using its index as a parameter. You will see how all this works soon. To make use of the created CelebritySource, add the following method to the ShowAll page class:
  public GridDataSource getCelebritySource() { return new CelebritySource(dataSource); } page of results, the Grid component invoked the methods of the GridDataSource implementation provided by its source parameter in a certain succession. The output shows that the prepare method was invoked with the indexFrom parameter set to 0, and the indexTo parameter set to 4. These are indexes of precisely how a database (or other data source) should be called, and we can request data, page-by-page by creating an implementation of GridDataSource interface. The Grid component will then invoke the methods of this interface and display the information returned by them appropriately. Next, we are going to see another advanced component, BeanEditForm. It is somewhat similar to Grid in that it also can make use of BeanModel, and its confi guration is pretty similar too.
  BeanEditForm Component
  Our current collection of celebrities is tiny, and it would be a good idea to provide in the application functionality for adding new celebrities. Let’s begin by adding a template and a page class for a new page named AddCelebrity. Add to the page class a single persistent property named celebrity, so that its code looks like this:
  package com.packtpub.celebrities.pages; import com.packtpub.celebrities.model.Celebrity; import org.apache.tapestry.annotations.Persist; public class AddCelebrity { @Persist private Celebrity celebrity; public Celebrity getCelebrity() { return celebrity; } public void setCelebrity(Celebrity celebrity) { this.celebrity = celebrity; } }
  In the page template, declare one single component of type BeanEditForm and let its id be the same as the name of the property of the page class, in our case, celebrity:
  <html xmlns: <head> <title>Celebrity Collector: Adding New Celebrity</title> </head> <body> <h1>Adding New Celebrity</h1> <t:beaneditform t: </body> </html>
  We also need to somehow connect the new page to the rest of the application. For instance, we could add this new PageLink component somewhere at the bottom of the ShowAll page:
  <a href="#" t:Add new Celebrity </a><br/> <a href="#" t: Back to the Start Page </a>
  Finally, to make things more interesting, add another couple of properties to the Celebrity class (don’t forget to generate getters and setters for them): private String biography; private boolean birthDateVerified; Say we could store a brief biography in the fi rst property, and the second could be set to true whenever we verify in some way that the birth date is correct. Run the application, log in, and at the ShowAll page, click on the link leading to the new AddCelebrity page. You will see the BeanEditForm in all its glory:
  Isn’t it amazing how much can be done for us by Tapestry when we just drop one component onto the page, with virtually no! Well,
  the error message is somewhat misplaced at the moment, but we’ll deal with this problem later.
  Do you still remember that to obtain all this wealth of functionality, all we had to do is to insert a short line of markup into the page template? Here it is again:
  <t:beaneditform t:
  Tweaking BeanEditForm
  There are a few parameters that we could use to tweak the component. First of all, you will probably want the submit button to display a different label, not the default Create/Update. Nothing could be easier:
  <t:beaneditform t:
  You can also explicitly specify the object that BeanEditForm should work with, and use an arbitrary id:
  <t:beaneditform t:
  Although BeanEditForm made a lot of clever guesses, in many cases we shall want to somehow.
  The way we tidy up the BeanEditForm is very similar to what we did with the Grid component:
  <t:beaneditform t:
  The other change we might want to make is to change the control that is used for Biography. Even though the biography will be brief, a text box is not convenient for entering a long string. There is a much more convenient control for this purpose in HTML,
  <t:beaneditform t: <t:parameter <t:label <t:textarea t: </t:parameter> </t:beaneditform>
  In a way similar to what we did with the Grid component to override the default rendering of a certain column, we are using a:
  This is already better. If you think that you’d prefer to have more space for a biography, try this:
  <t:textarea t:
  As cols and rows attributes do not belong to parameters of Tapestry’s TextArea component, they will be simply passed to the resulting
  DateField Component
  This is a new addition that appeared only in the latest 5.0.6 version of Tapestry. Now we can use this beautiful, JavaScript-powered control without seeing even a single line of JavaScript.
  Let’s add one more piece of information to those that we already collect from the users at the Registration page—Date Of Birth. Add this table row to the template, perhaps straight under the controls used for gender selection:
  <tr> <td>Gender:</td> <td> <t:radiogroup t: <input type="radio" t: Male <input type="radio" t: Female </t:radiogroup> </td> </tr> <tr> <td>Birth Date:</td> <td> <input type="text" t: </td> </tr> We'll also need a property to store the selected date in the Registration page class: @Persist private Date dateOfBirth; public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; }
  Click on the small icon to the right, and in the beautiful calendar that opens you will be able to choose a date:
  However, by default the selected date will be displayed in the American format, like 10/31/07 for the 31st of October. What if you would rather prefer to see it in the European format, 31/10/07? We can use the format property of the DateField component to display the date how we like:
  <input type="text" t:
  You can also construct a completely different date format. For example, %b %e, %Y will produce the result Oct 31, 2007. For the complete list of formatting characters check. number of styles, but those related to BeanEditForm have t-beaneditor in their name, and those related to Grid contain t-data-grid. Let’s say we want to change the background of BeanEditForm to white, the surrounding border to green and give more space to the labels. Admittedly, I am not an expert in CSS, but it is not actually diffi cult to fi gure out what exactly should be changed. These are the two style defi nitions we shall want to tweak:
  DIV.t-beaneditor { display: block; background: #ffc; border: 2px solid silver; padding: 2px; font-family: "Trebuchet MS", Arial, sans-serif; } DIV.t-beaneditor LABEL { width: 10%; display: block; float: left; text-align: right; clear: left; padding-right: 3px; }
  The? It will be convenient to have a directory for all the assets of our web application, let’s name it appropriately, styles. It should be created at the root of the web application, on the same level where page templates are placed.
  To create it in NetBeans, right click on the Web Pages folder inside the project structure. Select New|File/Folder…, then Other in Categories and Folder in File Types. Click on Next, give the new folder a name, and then click on Finish. Now right click on the new styles folder and again select New|File Folder…. Choose Other for Categories, Empty File for File Types, click on Next and name the new file something like styles.css.
  In Eclipse, the sequence of actions will be similar, but the new styles folder should be added to the WebContent folder in the project structure.
  Now we can put the aforementioned style defi nitions into styles.css, and change them as required. Let’s try something like this:
  DIV.t-beaneditor { display: block; background: white; border: 2px solid green; padding: 2px; font-family: "Trebuchet MS", Arial, sans-serif; } DIV.t-beaneditor LABEL { width: 150px; display: block; float: left; text-align: right; clear: left; padding-right: 3px; }
  In fact, it should be enough to leave only the highlighted lines here as the other details were already specifi ed in the default style sheet. We can also influence the positioning of the Save button:
  input.t-beaneditor-submit { position: relative; left: 150px; }
  However, to see the changes, we need to make the new stylesheet available to the web page. Tapestry can inject an asset, be it a stylesheet or an image, into the page class when we ask it to do that, so let’s add to the AddCelebrity page class to the following lines of code:
  @Inject @Path("context:styles/styles.css") private Asset styles; public Asset getStyles() { return styles; }
  Finally, provide in the page template a link to the stylesheet:
  <head> <title>Celebrity Collector: Adding New Celebrity</title> <link rel="stylesheet" href="${styles}" type="text/css"/> <.