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.
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.
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>
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.)
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" />
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.)