Dear Wiki user,

You have subscribed to a wiki page or wiki category on "Tapestry Wiki" for 
change notification.

The following page has been changed by CraigStJean:
http://wiki.apache.org/tapestry/Tapestry51SpringJpaIntegration

New page:
== Goal ==
The end result should be a Tapestry 5 (5.1 in this case) application, making 
use of Spring with Spring Transactions, and JPA.
This example will be an incredibly simplified phone book application.

== Updating web.xml ==
To start we need to add our Spring XML files to the context-params of web.xml:
{{{
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
}}}

Then we need to update the Tapestry 5 filter to be 
org.apache.tapestry5.spring.TapestrySpringFilter

Finally we want to open our Entity Manager on page requests, so we add a filter 
(before the Tapestry filter) and filter-mapping:
{{{
<filter>
    <filter-name>JpaFilter</filter-name>
    
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>JpaFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
}}}

== Spring Beans XML File ==
We would like to use JPA exception translation, annotations, and transactions.  
We also need a Dao for our Person object.
{{{
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans";
       xmlns:context="http://www.springframework.org/schema/context";
       xmlns:jee="http://www.springframework.org/schema/jee";
       xmlns:tx="http://www.springframework.org/schema/tx";
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                           http://www.springframework.org/schema/context 
http://www.springframework.org/schema/context/spring-context-2.5.xsd
                           http://www.springframework.org/schema/jee 
http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
                           http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd";>
    <bean 
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"
 />
    <context:annotation-config />
    
    <bean id="entityManagerFactory" 
class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="tapestryUnit" />
    </bean>
    <!-- Switch to this in JEE -->
    <!-- <jee:jndi-lookup id="entityManagerFactory" 
jndi-name="persistence/tapestryUnit" /> -->

    <bean id="transactionManager" 
class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    
    <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="personDao" class="com.company.myproject.dao.impl.PersonDaoImpl" />
</beans>
}}}

== persistence.xml ==
Our persistence.xml is the same as any other.  In this case we are not 
deploying to a JEE container, but just a web container, so we've defined the 
connection properties inside persistence.xml.  We typically would use 
connection pooling, but for simplicity we have not.  Note we will use Hibernate 
(though we don't have to!), and DB2.
{{{
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"; version="1.0">
    <persistence-unit name="tapestryUnit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>com.company.myproject.entities.Person</class>
        <exclude-unlisted-classes />
        
        <properties>
            <property name="hibernate.dialect" 
value="org.hibernate.dialect.DB2Dialect" />
            <property name="hibernate.connection.driver_class" 
value="com.ibm.db2.jcc.DB2Driver" />
            <property name="hibernate.connection.username" value="tapestry" />
            <property name="hibernate.connection.password" value="tapestry" />
            <property name="hibernate.connection.url" 
value="jdbc:db2://dbserver:50000/TESTS:currentSchema=PHNPRJ;" />
            <property name="hibernate.show_sql" value="true" />
        </properties>
    </persistence-unit>
</persistence>
}}}

== The DAO ==
Our DAO is just like any other JPA with Spring annotations DAO.

The entity the DAO will control is:
{{{
@Entity
@Table(name = "PERSON")
public class Person implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "ID")
    private Long id;

    @Version
    @Column(name = "VER")
    private Integer version;

    @Column(name = "FIRSTNAME", length = 15, nullable = false)
    private String firstName;

    @Column(name = "LASTNAME", length = 15, nullable = false)
    private String lastName;

    @Column(name = "PHONENR", length = 10)
    private String phoneNumber;

    // ... SNIPPED GETTERS/SETTERS ...
}}}

Note that as I'm using an identity column, the database must be created 
properly.  hbm2ddl does not do this.  Use this DDL:
{{{
CREATE TABLE PHNPRJ.PERSON (
    ID INT NOT NULL GENERATED ALWAYS AS IDENTITY,
    VER INT NOT NULL DEFAULT 0,
    FIRSTNAME VARCHAR(15) NOT NULL DEFAULT '',
    LASTNAME VARCHAR(15) NOT NULL DEFAULT '',
    PHONENR VARCHAR(10) DEFAULT '',
    CONSTRAINT PERSON_PK PRIMARY KEY (ID)
);
}}}

The DAO interface:
{{{
public interface PersonDao {
    public List<Person> getPeople();
    public Person read(Long id);
    public Person save(Person person);
    public void delete(Long id);
    public void delete(Person person);
}
}}}

The DAO:
{{{
@Repository
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public class PersonDaoImpl implements PersonDao {
    @PersistenceContext
    private EntityManager entityManager;

    public List<Person> getPeople() {
        return entityManager.createQuery("from Person p order by p.lastName, 
p.firstName, p.phoneNumber").getResultList();
    }

    public Person read(Long id) {
        return (Person)entityManager.createQuery("from Person p where p.id = 
:id").setParameter("id", id).getSingleResult();
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public Person save(Person person) {
        if (person.getId() == null || person.getId() == 0) {
            entityManager.persist(person);
        } else {
            person = entityManager.merge(person);
        }
        return person;
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void delete(Long id) {
        entityManager.remove(read(id));
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    public void delete(Person person) {
        entityManager.remove(person);
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}
}}}

== The Rest ==
Everything else is standard Tapestry.  To get our DAO in a T5 page:
{{{
@Inject
private PersonDao personDao
}}}

We do not need anything special in our AppModule.

Note do not include the tapestry-hibernate module as we are not using 
hibernate.cfg.xml.

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to