JPA Eclipse + GlassFish + Oracle XE – Outside EJB Container
Introduction
This example details the configuration of JPA running in Eclipse, using EclipseLink and GlassFish 2.1 and Oracle XE.
Eclipselink therefore overrides the built in TopLink Essentials JPA in GlassFish 2.1.
Installation
- Install the latest Java JDK 1.6 release
- Install the Eclipse Galilieo Java EE package (includes EclipseLink)
- Install GlassFish 2.1
- Install the GlassFish Eclipse Plugin (see web notes about downloading/installing this)
- Download and install Oracle XE
Database Creation
In the Oracle XE database home page, click on Administration, then Manage Database Users, create database user. For testing purposes, you can give the user all roles and privileges, however you would not do this in a production environment. Note that in Oracle, creating a database user also creates an empty database schema, as the two terms are synonymous. A single Oracle XE database installation can have any number of schemas (users), all as distinct logical databases in the same database instance (container).
Connection Pool / JDB Resource Creation
Open the GlassFish administration web page (by default this is at http://localhost:4848) and log in (default is admin/adminadmin). Open Resources, JDBC, and click on Connection Pools – the text, not the adjacent arrow. This will display the connection pools in the RHS pane. Click on New. Name the pool JPATestPool. Select a resource type of javax.sql.datasource, and select Oracle as the database vendor. Click Next, then in the additional properties, set the following values :-
Property Name
|
Value
|
User |
Your XE database username |
Password |
Your XE database password |
URL |
jdbc:oracle:thin:@localhost:1521:xe |
Click Save to save the new connection pool.
Click on JDBC Resources in the left hand pane (again, the wording not the arrow), and click new to create a new resource. Select the conncetion pool just created in the dropdown list. For the JNDI name, enter jdbc/JPATestPool and click OK to save. Note that the JNDI name given must match the name given in the <non-jta-data-source> element value in persistence.xml.
Project Creation
- Create a new JPA project with the wizard. Select “GlassFish v2.1 Java EE 5” as the target runtime.
- Select either Default, Utility, or minimal for the configuration – this determines which facets are added to the project. Facets can be added later via the “Project Facets” page in the project properties.
All of the above configurations worked.
- Following this, a connectivity driver (for Oracle in this case) needs adding to Eclipse and then to the project as follows :-
Download ojdbc14.jar from Oracle.com here :-
http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/htdocs/jdbc_10201.html
- Copy the file to the glassfish\lib folder under the GlassFish installation directory and Restart GlassFish.
N.B. the jar file must be placed in this location
- Click on Window, preferences, and select Data Management, Connectivity, Driver Definitions in the left pane.
- Click Add, and assuming Oracle XE is in use, select “Oracle Thin Driver” for Oracle 10.
- Click on the Jar List tab. ojdbc14.jar should be listed. Browse for the above location where the actual jar was placed (<GlassFish_Home>\glassfish\lib) and select the jar from there.
The properties tab allows defaults to be set up for database connectivity, but these values will be added in GlassFish when the data source is created.
- Select Java Build Path in the project properties for the project you created above. Pick the libraries tab, and click Add Library. Click “Add Library” and select “Connectivity Driver Definitions” from the list. Select “Oracle thin Driver” from the drop down. If it is not present (i.e. because you did not create it correctly as above), you can click the button/icon to the right of the drop down and add the connectivity driver to Eclipse from there. Once done, you select it in the drop down then click finish to add it to the project.
Creating the Source Code
Create the following java classes in Eclipse by right clicking the “src” folder of the project and selecting New, Class. For the package name, enter uk.co.salientsoft.jpatest.domain. For the UserInfo class (which is the persisted class), the combined package and classname must match the value given in the <class> element in persistence.xml.
Class: JPATest
package uk.co.salientsoft.jpatest.domain;
import javax.persistence.*;
public class JPATest {
private static final String PERSISTENCE_UNIT_NAME = "JPATest";
private EntityManagerFactory factory;
public static void main(String[] args) {
JPATest jpaTest = new JPATest();
jpaTest.addEntries();
}
public JPATest() {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}
public void addEntries() {
EntityManager em = factory.createEntityManager();
// Begin a new local transaction so that we can persist a new entity
em.getTransaction().begin();
// Read the existing entries
Query q = em.createQuery("select u from UserInfo u");
// Do we have entries?
boolean createNewEntries = (q.getResultList().size() == 0);
// No, so lets create new entries
if (createNewEntries) {
UserInfo userInfo;
userInfo = new UserInfo();
userInfo.setUserName("Bilbo.Baggins");
em.persist(userInfo);
userInfo = new UserInfo();
userInfo.setUserName("Frodo.Baggins");
em.persist(userInfo);
}
// Commit the transaction, which will cause the entity to
// be stored in the database
em.getTransaction().commit();
// It is always good practice to close the EntityManager so that
// resources are conserved.
em.close();
}
}
Class: UserInfo
package uk.co.salientsoft.jpatest.domain;
import java.io.Serializable;
import javax.persistence.*;
/**
* Entity implementation class for Entity: UserInfo
*
*/
@Entity
public class UserInfo implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private long userID;
private String userName;
private static final long serialVersionUID = 1L;
public UserInfo() {
super();
}
public long getUserID() {
return this.userID;
}
public void setUserID(long userID) {
this.userID = userID;
}
public String getUserName() {
return this.userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
Persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
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">
<persistence-unit name="JPATest" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<non-jta-data-source>jdbc/JPATestPool</non-jta-data-source>
<class>uk.co.salientsoft.jpatest.domain.UserInfo</class>
<properties>
<property name="eclipselink.target-server" value="None" />
<property name="eclipselink.logging.level" value="FINEST" />
<property name="eclipselink.session-name" value="JPATestSession" />
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
</persistence>
Notes on Persistence.xml
<persistence-unit name="JPATest" transaction-type="RESOURCE_LOCAL">
The persistence unit defines a related grouping of classes, metadata etc. which are being persisted .
NOTE – ensure that the value matches the one passed to createEntityManagerFactory in the code, or the call causes a stack trace citing no persistence provider found – all the available persistence providers are tried and listed and they all return null. They are all tried to see if they support the given persistence unit (i.e. are they listed as the provider for that persistence unit in persistence.xml) hence the error.
Transaction-type needs to be ”RESOURCE_LOCAL” if jpa is used outside the EJB container, in which case the datasource is defined as a <non-jta-data-source>. Note that the datasource in this case is still defined in GlassFish.
The alternative for jpa usage inside the conainer , e.g. from a session bean, would be to defined transaction-type as “JTA” and the datasource as a <jta-data-source>.
<property name="eclipselink.target-server" value="None" />
Note that with JPA inside the container, the above property would have the following value :-
<property name="eclipselink.target-server" value="SunAS9" />
When set to “SunAS9”, you must use a JTA data source and JTA transaction type or you get an error. When you use “None” you can use <non-jta-data-source> and “RESOURCE_LOCAL”, but note that you can still refer to the data source defined in GlassFish, or you can define one explicitly in persistence.xml. You could define one explicitly in persistence.xml as follows :-
<property name="eclipselink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:xe"/>
<property name="eclipselink.jdbc.user" value="jpatest"/>
<property name="eclipselink.jdbc.password" value="jpatest"/>
<property name="eclipselink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
The mechanism used to drop and create the tables automatically (“drop-and-create-tables” value) is jpa provider dependant (and may not always be available). When it is used with EclipseLink as above, a stack trace with a number of errors is dumped when it tries to drop non existant tables etc., and due to other issues. If you check in Oracle XE and can see the tables and the data, the errors can be ignored. The drop and create only needs to be done once to create the tables. You can remove this property from persistence.xml to prevent the tables being dropped and created each time. Note that this can also be done directly from Eclipse via the project context menu, as detailed here.
Running the application
- In Eclipse, select Window, Show View, Servers. If GlassFish is not listed, right click the server window and select New Server. Then Select GlassFish 2.1 Java EE 5. Click Next, and browse for the <GlassFish_Home>\glassfish directory (leave the JRE as the default).
- Right click the server in the servers view, then select start to start it if it is not running.
- Right click on JPATest.java and select Run as, then Java application.
- The application should then run and populate the database. Log in to the XE database home page as the user/schema you created, and click on the object browser.
- Click on the UserInfo table and you should see the rows which were created.