Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: restore

Scrollbar

So, you fill in all the fields, submit the form (without validation errors) and voila: you get back the same form, blanked out. What happened, and where did the data go?

...

First, we must update the POM to list a new set of dependencies, that includes Hibernate, the Tapestry/Hibernate integration library, and the HSQLDB JDBC driver:

Code Block
languagexml
titlesrc/pom.xml (partial)
    <dependencies>

        <dependency>
            <groupId>org.apache.tapestry</groupId>
            <artifactId>tapestry-hibernate</artifactId>
            <version>${tapestry-release-version}</version>
        </dependency>

        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.3.2</version>
        </dependency>
        ...
    </dependencies>

The tapestry-hibernate library includes, as transitive dependencies, Hibernate and tapestry-core. This means that you can simply replace "tapestry-core" with "tapestry-hibernate" inside the <artifactId> element.

...

Hibernate needs a master configuration file, hibernate.cfg.xml, used to store connection and other data. Create this in your src/main/resources folder:

Code Block
languagexml
titlesrc/main/resources/hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="hibernate.connection.url">jdbc:hsqldb:./target/work/t5_tutorial1;shutdown=true</property>
        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
    </session-factory>
</hibernate-configuration>

Most of the configuration is to identify the JDBC driver and connection URL.

...

Below is the updated Address class, with the Hibernate annotations (as well as the Tapestry ones).

Code Block
languagejava
titlesrc/main/java/com/example/tutorial/entities/Address.java
package com.example.tutorial1.entities;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.apache.tapestry5.beaneditor.NonVisual;
import org.apache.tapestry5.beaneditor.Validate;

import com.example.tutorial1.data.Honorific;

@Entity
public class Address
{
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @NonVisual
  public Long id;

  public Honorific honorific;

  @Validate("required")
  public String firstName;

  @Validate("required")
  public String lastName;

  public String street1;

  public String street2;

  @Validate("required")
  public String city;

  @Validate("required")
  public String state;

  @Validate("required,regexp")
  public String zip;

  public String email;

  public String phone;
}

The Tapestry annotations, @NonVisual and @Validate, may be placed on the setter or getter method or on the field (as we have done here). As with the Hibernate annotations, putting the annotation on the field requires that the field name match the corresponding property name.

...

Let's update our CreateAddress.java class:

Code Block
languagejava
titlesrc/main/java/com/example/tutorial/pages/address/CreateAddress.java
package com.example.tutorial1.pages.address;

import com.example.tutorial1.entities.Address;
import com.example.tutorial1.pages.Index;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Session;

public class CreateAddress
{
    @Property
    private Address address;

    @Inject
    private Session session;

    @InjectPage
    private Index index;

    @CommitAfter
    Object onSuccess()
    {
        session.persist(address);

        return index;
    }
}

The Inject annotation tells Tapestry to inject a service into the annotated field; Tapestry includes a sophisticated Inversion of Control container (similar in many ways to Spring) that is very good at locating available services by type, rather than by a string id. In any case, the Hibernate Session object is exposed as a Tapestry IoC service, ready to be injected (this is one of the things provided by the tapestry-hibernate module).

...

As a little preview of what's next, let's display all the Addresses entered by the user on the Index page of the application. After you enter a few names, it will look something like:

Image RemovedImage Added

Adding the Grid to the Index page

...

A minimal Grid is very easy to add to the template. Just add this near the bottom of Index.tml:

Code Block
languagexml
titlesrc/main/webapp/Index.tml (partial)
  <t:grid source="addresses"
         include="honorific,firstName,lastName,street1,city,state,zip,phone"/>

Note that the Grid component accepts many of the same parameters that we used with the BeanEditForm. Here we use the include parameter to specify the properties to show, and in what order.

Now all we have to do is supply the addresses property in the Java code. Here's how Index.java should look now:

Code Block
languagejava
titlesrc/main/java/com/example/tutorial/pages/Index.java
package com.example.tutorial1.pages;
import java.util.List;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Session;
import com.example.tutorial1.entities.Address;
public class Index
{
    @Inject
    private Session session;
    public List<Address> getAddresses()
    {
        return session.createCriteria(Address.class).list();
    }
}

Here, we're using the Hibernate Session object to find all Address objects in the database. Any sorting that takes place will be done in memory. This is fine for now (with only a handful of Address objects in the database). Later we'll see how to optimize this for very large result sets.

...

Check out the many Tapestry resources available on the Documentation Using Tapestry With Hibernate page, including the Getting Started Using Tapestry With Hibernate and FAQ pages and the Cookbook Using Tapestry With Hibernate. Be sure to peruse the User Guide Using Tapestry With Hibernate, which provides comprehensive details on nearly every Tapestry topic. Finally, be sure to visit (and bookmark) Tapestry JumpStart, which provides a nearly exhaustive set of tutorials.

 

Scrollbar