Using Java Persistence API in application client in Java EE platform
In Java EE 5 platform Java Persistence API can be used in three types of containers, viz: ejb, web and application client container. In my earlier blogs, I had talked about using this API in web applications and in EJB applications. This time we will talk about using Java Persistence API in application clients. We also discuss about two different way of packaging the application. You can download the complete sample, unzip and run 'ant deploy' to see the sample in action. The steps are very simple as discussed below:
Step #1: Write entity bean UserCredential.java
In my previous articles I have discussed about structure of an entity bean class. So I am not going to repeat them here.
Step #2: Define a persistence unit in persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name ="pu1" transaction-type="RESOURCE_LOCAL"/> </persistence>
Points to note about this persistence.xml are:
1) One persistence.xml can be used to define multiple PUs, but in this case we have defined only one PU by name pu1.
2) We need not specify any elements/attributes other than transaction-type, as the default values are just fine. By default the entity manager's transaction type is JTA. Since Application Client Container is not required to support JTA, we can not use JTA entity managers in this example. So we have set it to RESOURCE_LOCAL here.
3) There is no need to enumerate all the entity bean class names inside because we are defining only one PU in this persistence.xml and we will be packaging the entity classes along with this persistence.xml in a jar file, so container can discover all the entity beans.
Step #3: Write Client.java
Points to note about this appclient are that:
1) It declares dependency on the PersistenceUnit using @PersistenceUnit as shown below:
@PersistenceUnit private static EntityManagerFactory emf;
Also note that, the field ucm is static. More discussion on this further below. Secondly, there is only one PU visible to this application client, hence there is no need to specify the unitName attribute in @PersistenceUnit.
2) It must be a public class because it will be used by ACC which does not belong to the package of this class.
3) We also need to write a manifest.mf file which must contain the name of the class containing the main().
4) The rest of the client class is simple. It creates an EntityManager using the injected EntityManagerFactory. It closes it at the end of the application. Since we can't use JTA, the client uses EntityTransaction API to manage transactions.
5) There is no need to write application-client.xml because it is optional. Java EE 5 compatible platform can discover appclient.jar's module type because it contains META-INF/MANIFEST.MF with a Main-Class attribute.
Step #4: Build and package the application using build.xml
When using entity beans in appclient, we have two packaging options:
Option #1: package the entity beans and the persistence.xml in a jar file (say) entities.jar. Package the appclient main class along with its manifest.mf in a separate jar (say) appclient.jar. Put both these jars into an ear file. So the final ear file looks like this:
jpa_acc_option1.ear lib/entities.jar (contains only entity classes) appclient.jar (contains only client main class and manifest file)
Since the entities.jar is placed in the EAR lib directory, it is automatically added to CLASSPATH while running the appclient. So, no need to use Class-Path manifest entry.
Option #2: package the entity beans and the persistence.xml in the appclient.jar along with appclient main class. No need to make an ear file in this case, as we can just deploy the appclient.jar. The appclient.jar contains following entries:
appclient.jar: META-INF/MANIFEST.MF (this contains Main-Class attribute) META-INF/persistence.xml example/client/Main.class example/entity/UserCredential.class
To demonstrate this, there are two build targets, viz: build-app1 and build-app2. The third build target internally call these two targets. Same goes for deploy and verify targets.
Both of the packaging alternatives discussed here are completely portable. It is upto you to decide which of the options you want to use.
Step #5: Run the application
As we mentioned, there are two different applications here. Depending on which application you want to use, the option passed to appclient command is slightly different as the name of the generated jar file is different.
To run the first application client:
$GLASSFISH_HOME/bin/appclient -client $GLASSFISH_HOME/domains/domain1/generated/xml/j2ee-apps/jpa_acc_option1/jpa_acc_option1Client.jar foo bar
To run the second application client (see different generated jar file name):
$GLASSFISH_HOME/bin/appclient -client $GLASSFISH_HOME/domains/domain1/generated/xml/j2ee-modules/jpa_acc_option2/jpa_acc_option2Client.jar foo bar
Use of Java2DB
Please see I don't have instructions to create tables etc. I like to use
a feature called Java2DB in my development environment. Although there are more than one way of using Java2DB, I like to use it by passing --createtables option to asadmin deploy command. See build.xml for more info. This feature is specific to Sun's app server.
Why injected field or method must be static in application client?
When we package the application client, we specified the main class name using Main-Class attribute in manifest file. The entry point for an Applicaiton Client component is the static main method of that main class, so there is no instance.
ACC does not create any instance of that class. So the injected fields or methods have to be static.
An implementation of the Java Persistence API is being done in GlassFish project. GlassFish was supporting Java Persistence API in EJB and Web containers for quite some time now. Only recently, we have just integrated the Java Persistence API support in Application Client Container. As I am writing this blog, we still have not promoted a build that has this change. So you have to use one of the latest nightly builds to run this example.
Although I am using GlassFish to build and run this sample, atmost you have to do some minor confiuration to persistence.xml and build.xml to make this app build and run in any other application server that supports Java EE 5 specification. This sample also uses a proprietary feature called Java2DB. But that does not make this a non-portable application as I am using it only during deployment.
Hope you found this example useful.