Developing Great Software

Sunday, April 5, 2009

JPA/Hibernate and Wicket Repeating Views with Netbeans- Part 2

[***Note This is the second and final article in this series and requires that you have completed the exercises in the first article in this series. If you haven't already, please do so now before preceding with the exercises in this article.] This is the second and final article in this series of using JPA/Hibernate and Wicket repeating views. This article will cover the remaining tasks that will allow us to render the the data from the Customer table in a tabular view to the browser using Apache Wicket repeating views and models. Wicket's Repeating Views Wicket's repeating views allow you to render data from a collection of objects, such as a List. HTML tables can be used to display the information in the browser where each row in the table represents one item in the List collection and columns in the table represent each List item's fields. The markup we want to generate for this exercise is an HTML table with the following elements:
  • A table header with header columns for each of the columns from the Customer table that we want to display. For our exercise, we will display the Customer ID, Customer Discount Code, Customer Zip, and Customer Name columns from the Customer table.
  • A table row for each of the Customer entities returned when we query the Customer table for its contents. The cells in these rows will contain data from their corresponding fields in the Customer entity objects that are returned when we query the Customer table. Their corresponding fields are customerId, discountCode, zip, and name.
[***Note Because there is a one-to-many relationship between the Customer entity and the DiscountCode entity, the customer's discount code can be referenced through the Customer entity. We will see this later when we write the code to actually render the data to the browser.] Wicket provides numerous components that render content and markup to the browser. Among these are repeating view components that repetitively render the same markup but with varying content depending on the current item associated with the current view. The item associated with current view in our example is the current Customer entity from a List of Customer entities that we want to render. Models - IModel and IDetachable Wicket's components access data through models. This is the Model part in Wicket's Model View Controller implementation. Models are wrappers around data; they keep a reference to the data they are wrapping. Wicket provides numerous models such as Model, PropertyModel, CompoundPropertyModel, and LoadableDetachableModel to name a few. All models must implement the IModel interface, which publishes two methods:
  • T getObject() - returns and object of type T.
  • void setObject(T object) - set the model data to object of type T.
IModel also extends the IDetachable interface which publishes one method:
  • void detach() - detaches the model data and is called after rendering has completed.
Wicket Is A Stateful Framework Wicket is a stateful web framework; at the end of a request, after the markup has been sent to the browser, Wicket stores the page, component hierarchy, and associated models (state) in the page store. Since models keep references to their data, data will also be stored if it hasn't been detached from the model first. In order for the data to be stored it must be serializeable. Detaching the data from a model reduces the memory overhead on the server and also allows models to be associated with data that isn't serializeable. LoadableDetachableModel Wicket provides an abstract implementation of a detachable model, LoadableDetachableModel.
It is a model that can be serialized to the page store without its data; its reference to its data is declared as transient. It implements IModel and IDetachable. LoadableDetachableModel calls its load method when the view component it is attached to needs access to its data. This allows clients, which implement this method, to load the data it wraps from any data source, a database for instance. We will see an example of using the LoadableDetachableModel later in the exercise when we implement the code for the view. DataView The DataView is a repeating view component. It makes it very simple to populate a repeating view from a database. DataView's are constructed as follows:
  • protected DataView(String id, IDataProvider dataProvider)
  • protected DataView(String id, IDataProvider dataProvider, int itemsPerPage)
Both constructors take an id of String as their first parameter. Its value must be set to the wicket:id attribute of the HTML tag we are attaching the DataView component to. Both constructors take an IDataProvider as their second parameter. The IDataProvider acts as an interface between the database and the Dataview. itemsPerPage, an int, can be passed as a third parameter and is used when implementing pagination. For this article, we will use the first constructor, which takes only two parameters, an id and an IDataprovider. The IDataProvider Interface - a wrapper around data
IDataProvier is really nothing more than a wrapper around a collection. It extends IDetachable and publishes three methods that must be implemented:
  • iterator(int first, int count) - Gets an iterator for the subset of total data.
  • model(T object - Callback used by the consumer of this data provider to wrap the object retrieved from the iterator(int, int) with a model (usually a detachable one).
  • size() - Gets the total number of items in the collection represented by the DataProvider.
Implementing an IDataProvider Below is the implementation of IDataProvieder that will be used by our DataView component: Let's discuss each of the methods in our implementation of IDataProvider:
  • iterator calls the CustomerJpaController's findCustomerEntities method with 2 parameters, count and first and will return an Iterator for the list of Customer objects that the findCustomerEntities method returns.
  • size calls the CustomerJpaController's getCustomerCount method to get the count of Customers and returns the result.
  • model creates and returns an anonymous LoadableDetachableModel object which wraps our Customer entity object which will be detached after rendering has completed.
  • detach has an empty implementation because we do not have any models directly associated with our implementation of IDataProvider that need to be detached.
We create an anonymous instance of the DataView component and add it to our HomePage as follows:
There are a few things to notice in the above code:
  • We are attaching the DataView to an HTML element whose wicket:id is rows. We will discuss the HomePage.html markup later.
  • populateItem will be called by the DataView component for each Customer object provided by customerDataProvider.
  • We are using a CompoundPropertyModel to bind the fields in the the Customer object to the four Label components. The field in the Customer object is identified by the id we pass to each Label's constructor.
  • Because there is a 1 to many relationship between the Customer and the DiscountCode entity objects, we must use discountCode.discountCode to reference the discountCode field in the DiscountCode entity associated with the Custmoer entity.
Here is the complete code for HomePage.java: Here is the complete markup for HomePage.html. Notice how each of the wicket:id attribute values match the id values we passed to our DataView and four Labels : Add some styling to our page Lets add some styling to our page:
  1. Right click the Web Pages node in the Projects pane and select New | Other which will open the New File window.
  2. Select Web from the Categories pane and select Cascading Style Sheet from the File Types pane and click Next.
  3. Enter style for the CSS File Name and click Finish which will open the style.css file in the editor.
Add the following styling attributes to the style.css file:Modify CustomerJpaController Lets modify the JPA query in the CustomerJpaController class to return our Customer entities in ascending CustomerId order:
  1. Fully expand the Source Packages node in the Projects pane and double click the CustomerJpaController node. This will open the file in the editor.
  2. Locate the findCustomerEntities(boolean all, int maxResults, int firstResult) method and add order by o.customerId to the JPA query string.
The complete code for the method should now look like the following: Now lets run the project. Run the project Run the project by right clicking the project node in the Projects pane and selecting Run which will open your browser and render the following:Summary
  • We create a Wicket DataView to render repeating data in an HTML table to the browser.
  • We implement an instance of IDataProvider to act as an interface between the database and the DataView.
  • Our implementation of IDataProvider's model method creates and returns a LoadableDetachable model.
  • We assign a CompoundPropertyModel to the view, wrapping the Customer object.
  • We create four Label components. Each is bound to a field in the Customer object. The field in the Customer object is identified by the id we pass to each Label's constructor.
  • We modified our JPA query to return our Customer entities in customerId order.
Well, that concludes our discussion of working with JPA/Hibernate and Wicket repeating views with Netbeans. Please note that you are not limited to using Hibernate as your persistence provider; the same principles we applied here will work with any JPA compatible persistence provider, such as EclipseLink. Similarly, these techniques will work with a number of database systems, such as MySql for example. In a future post, I will discuss what I believe to be is a more efficient, effective and easier method of working with JPA and Wicket. Using Netbeans v6.5 I will demonstrate how to create a Java EE5 enterprise application and create EJBs that provide back-end database services through dependency injection to a Wicket web application. Stay tuned!

5 comments:

  1. Jeff, this is an excellent post, exactly what I needed :)

    When do we expect your follow up post as mentioned in the last para ?

    ReplyDelete
  2. Never mind, found the blog post, thanks!

    ReplyDelete

Note: Only a member of this blog may post a comment.

About Me

My photo
New York, NY, United States
Software Developer