5.3 Building the JPA module
Prev | 5. The Middle Tier | Next

## 5.3 Building the JPA module

In this section the JPA module in GreenPages is created, building upon an existing skeleton. JPA and its metadata are configured, and a JPA-based Directory service implementation is published which is then consumed by the application’s Web bundle.

### Completing the JPA-based Directory implementation

The `greenpages.jpa` starter project provides the beginnings of a JPA-based implementation of `Directory` named `JpaDirectory`. Import the `greenpages.jpa` project from the `$GREENPAGES_HOME/start` directory.

Open the `JpaDirectory.java` source file in the `greenpages.jpa` package of `greenpages.jpa` project (under `src/main/java`).

The source file contains a Java Persistence Query Language (JPQL) search query that will be used to retrieve listings from the database, and empty implementations of the `search` and `findListing` methods.

First add an `EntityManager` to it. Before the new field can be added, `EntityManager` must be available on the classpath. Open the pom for `greenpages.jpa` and add the following dependency:

            <dependency>
                <groupId>javax.persistence</groupId>
                <artifactId>com.springsource.javax.persistence</artifactId>
            </dependency>

Now return to `JpaDirectory` and add the following field to the class along with an import for `javax.persistence.EntityManager` (which should be suggested by Eclipse):

        private EntityManager em;

This `EntityManager` can now be used to implement the `search` and `findListing` methods. Update the implementations of these two methods to match the following implementations and then save the updated class:

       public Listing findListing(int id) {
            return em.find(JpaListing.class, id);
        }

        @SuppressWarnings("unchecked")
        public List<Listing> search(String term) {
            return em.createQuery(SEARCH_QUERY).setParameter("term",
                    "%" + term.toUpperCase() + "%").getResultList();
        }

(Warnings from Eclipse should now be absent.)

The application context now needs to be updated to create `JpaDirectory` and to create an `EntityManager` that can be injected into `JpaDirectory`.

Open `module-context.xml` in the `META-INF/spring` folder of the `greenpages.jpa`. Add the following beans that will create `JpaDirectory` and an `EntityManager`, enable load-time weaving that is required by JPA, and enable annotation-based configuration that will allow the `EntityManager` to be injected into `JpaDirectory`:

        <!--
            Activates a load-time weaver for the context. Any bean within the
            context that implements LoadTimeWeaverAware (such as
            LocalContainerEntityManagerFactoryBean) will receive a reference to
            the autodetected load-time weaver.
        -->
        <context:load-time-weaver aspectj-weaving="on" />

        <!-- JPA EntityManagerFactory -->
        <bean id="entityManagerFactory"
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
            p:dataSource-ref="dataSource">
            <property name="jpaVendorAdapter">
                <bean id="jpaVendorAdapter"
                    class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"
                    p:databasePlatform="org.eclipse.persistence.platform.database.HSQLPlatform"
                    p:showSql="true" />
            </property>
        </bean>

        <!--
            Activates various annotations to be detected in bean classes: Spring's
            @Required and @Autowired, as well as JSR 250's @PostConstruct,
            @PreDestroy and @Resource (if available) and JPA's @PersistenceContext
            and @PersistenceUnit (if available).
        -->
        <context:annotation-config />

        <bean id="directory" class="greenpages.jpa.JpaDirectory" />

The addition of the new beans to the context has introduced a new dependency upon Spring’s ORM support and upon EclipseLink and its JPA implementation. Add the following dependencies to the pom file for `greenpages.jpa` and save it:

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>org.springframework.spring-library</artifactId>
                <type>libd</type>
            </dependency>
            <dependency>
                <groupId>org.eclipse.persistence</groupId>
                <artifactId>com.springsource.org.eclipse.persistence</artifactId>
            </dependency>
            <dependency>
                <groupId>org.eclipse.persistence</groupId>
                <artifactId>com.springsource.org.eclipse.persistence.jpa</artifactId>
            </dependency>

Now switch back to `module-context.xml` for `greenpages.jpa` and observe that the errors relating to Spring’s ORM types have now been resolved. Save `module-context.xml`.

The application context now contains a factory that will create an `EntityManager` and is configured for annotation-based configuration. The last step in completing `JpaDirectory` is to annotate the `EntityManager` field so that Spring will inject the `EntityManager` created by the factory into the field.

Open `JpaDirectory.java` again and add an annotation `@PersistenceContext` to the `EntityManager` field.

    @PersistenceContext
    private EntityManager em;

Eclipse will suggest an import for `javax.persistence.PersistenceContext`; accept this and save the file.

### Providing the JPA metadata

JPA uses a file named `META-INF/persistence.xml` to describe persistence units. `persistence.xml` refers to a second file, typically named `META-INF/orm.xml`, to define entity mappings. In the case of GreenPages the `persistence.xml` file specifies a single persistence unit that points to the `greenpages.JpaListing` class. The specified mapping file (`META-INF/orm.xml`) tells the JPA implementation how to map `JpaListing` to the `LISTING` database table described above. (For more information on JPA consult the Documentation section in the appendix.)

Create a new file named `persistence.xml` in the `META-INF` folder of the `greenpages.jpa` project. Add the following contents to the new file and then save it:

    <?xml version="1.0" encoding="UTF-8" ?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                            http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
        version="1.0">

        <persistence-unit name="GreenPages" transaction-type="RESOURCE_LOCAL">
            <class>greenpages.jpa.JpaListing</class>
        </persistence-unit>

    </persistence>

Now create a new file named `orm.xml` also in the `META-INF` folder alongside `persistence.xml`. Add the following contents to the new file and then save it:

    <?xml version="1.0" encoding="UTF-8" ?>
    <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm
                            http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
        version="1.0">
        <package>greenpages.jpa</package>
        <entity class="greenpages.jpa.JpaListing" name="Listing">
            <table name="LISTING" />
            <attributes>
                <id name="listingNumber">
                    <column name="LISTING_NUMBER" />
                    <generated-value strategy="TABLE" />
                </id>
                <basic name="firstName">
                    <column name="FIRST_NAME" />
                </basic>
                <basic name="lastName">
                    <column name="LAST_NAME" />
                </basic>
                <basic name="emailAddress">
                    <column name="EMAIL_ADDRESS" />
                </basic>
            </attributes>
        </entity>
    </entity-mappings>

### Consuming the DataSource from the service registry

The `entityManagerFactory` bean that was added earlier depends upon a bean named `dataSource` which it will use to connect the `EntityManager` to the GreenPages database. The `greenpages.db` module already publishes a `DataSource` to the service registry. `greenpages.jpa` must now be updated to consume this.

Open `osgi-context.xml` in the `META-INF/spring` folder of the `greenpages.jpa` project and add the following:

        <!-- import the DataSource from OSGi -->
        <osgi:reference id="dataSource" interface="javax.sql.DataSource" />

This will result in a bean being created in the application context that is named `dataSource`. The bean will be of type `javax.sql.DataSource` and will be backed by a service found in the OSGi service registry that implements the `javax.sql.DataSource` interface. (Some warnings concerning the `dataSource` bean will now disappear.)

### Publishing the Directory implementation to the service registry

To make the JPA-based `Directory` implementation available to GreenPages’ Web module it must be “published” to the OSGi service registry.

Open `osgi-context.xml` in the `META-INF/spring` folder of the `greenpages.jpa` project, add the following and then save the updated file:

        <!-- export the directory bean to OSGi under the Directory interface -->
        <osgi:service ref="directory" interface="greenpages.Directory" />

### Generating greenpages.jpa’s manifest using Bundlor

Open the `template.mf` file in the root of the `greenpages.jpa` project and switch to the `template.mf` tab. Add the following entries to the template and save it.

    Import-Bundle: com.springsource.org.eclipse.persistence;version="[1.0.0,1.0.0]",
     com.springsource.org.eclipse.persistence.jpa;version="[1.0.0,1.0.0]"
    Import-Package: org.springframework.context.weaving;version="[3.0,3.1)",
     org.springframework.transaction.aspectj;version="[3.0,3.1)"
    Excluded-Exports: greenpages.jpa

The `Excluded-Exports` header tells Bundlor that the `greenpages.jpa` should not be exported from the `greenpages.jpa` bundle.

The `Import-Package` entries for `org.springframework.context.weaving` and `org.springframework.transaction.aspectj` are needed as Bundlor cannot, yet, detect that these packages are required.

Lastly, the `Import-Bundle` entries for EclipseLink and its JPA implementation are needed as Bundlor cannot, yet, detect that EclipseLink is the JPA implementation that is being used by GreenPages.

Switch to the Overview tab and click Update MANIFEST.MF. As with `greenpages.db` before, this update may result in some errors being reported in the manifest as the project is not associated with a targetted runtime. Double-click the `MANIFEST.MF` file in the `greenpages` project in the Package Explorer. Switch to the Dependencies tab and click Add…. Select `greenpages.jpa` and click OK. Save the updated file. The problems in the manifest should now be resolved and the GreenPages application should be redeployed due to the addition of the `greenpages.jpa` module. This redeployment should succeed and it’s now time to try the application again.

(A possible action if this fails is to Update (Maven) Dependencies on the project right-click menu in the Maven sub-menu.)

Prev | Up | Next
5.2 Creating the DataSource project | Home | 5.4 Trying out the JPA middle tier