Java J2EE Portal
Enterprise Java Station
J2EE curve
Java News / Articles
Java News / Articles
Quick Introduction To Agile Software Development
Ajax And Web 2.0 Panel Discussion
Using Apache Geronimo In Real World JavaEE Applications
Processing...
Buy Java, Deals On Software Technology Store
Click here for great deals on computers, laptops, software and books
Building Advanced Components For Tapestry Web Applications PDF Print
Written by Alexander Kolesnikov   
Feb 14, 2008 at 02:50 AM

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 first two parameters—indexFrom and indexTo, which are the indexes of the first 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 to de fine the column by which the result should be sorted.
Again, we could use this parameter in a SELECTstatement, but here we are simply outputting the name of the property to see what the Grid has passed to the method. Finally, the ascending parameter could be used to de fine 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);
}

Then change the source parameter of the Grid component in ShowAll.tml template:

<t:grid t:source="celebritySource" rowsPerPage="5" row="celebrity" t:model="model">

Run the application. Log in to view the ShowAll page, and as soon as the table with
celebrities is displayed, you should see the following output:
Preparing selection.
Index from 0 to 4
Property name is: null
Sorting order ascending: true
Getting value for row 0
Getting value for row 1
Getting value for row 2
Getting value for row 3
Getting value for row 4

From this you can see that to display the first 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 the first five celebrities in collection. The propertyModel parameter was null, so no speci fic sorting was requested. Finally, the getRowValue method was invoked five times to obtain an object to be displayed by each of the five rows in the table.

Click on the pager to view the second page of results and the result will be similar, only the indices will be different:
Preparing selection.
Index from 5 to 9
Property name is: null
Sorting order ascending: true
Getting value for row 5
Getting value for row 6
Getting value for row 7
Getting value for row 8
Getting value for row 9

Click on the header of one of the columns, and you will see the change in the property name passed to the prepare method:
Property name is: lastName
Sorting order ascending: true
Now the data source will be requested to sort the result by last name. Of course, no sorting will take place in our simpli fied example as we are simply outputting the name of the property and not using it in an actual request to a database.

Click on the same column once again, and this time you will see that the order of sorting is changed:
Property name is: lastName
Sorting order ascending: false

You can see from this example that Tapestry allows us to de fine 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 con figuration 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:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
  <head>
    <title>Celebrity Collector: Adding New Celebrity</title>
</head>
<body>
   <h1>Adding New Celebrity</h1>
   <t:beaneditform t:id="celebrity"/>
</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:type="PageLink" t:page="AddCelebrity">Add new Celebrity
</a><br/>
<a href="#" t:type="PageLink" t:page="Start">
     Back to the Start Page
</a>

Page 3 Of 6 - Advanced Components from the book "Tapestry 5 - Building Web Applications"



Add This Feed Button

Enter your Email

IndicThreads.com Conference On Java Technology, Pune, India
Java Expert Interviews
JonathanAgileXPSoftwareTestingX
The good and bad of XP and Agile notions of software testing
JonasJacobiJSFAjax
Pure Ajax creates the next generation legacy applications
HTML 5 WebSocket cracks the HTTP request-response barrier
Processing...
Go to top of page  Home |
SiteMap

Copyright 2004 to 2008 Rightrix Solutions. All rights reserved. All product names are trademarks of their respective companies. Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Rightrix Solutions and IndicThreads.com are independent of Sun Microsystems, Inc.

Views expressed at IndicThreads.com reflect the views of the authors alone, and do not necessarily reflect those of IndicThreads.com. IndicThreads.com and it's authors are not responsible for reader comments and opinions.

Enterprise Java J2EE JEE Portal >> IndicThreads.com