Using Java Persistence API in application client in Java EE platform
Posted by ss141213 on March 21, 2006 at 01:03 AM | Comments (7)
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.
Software Required
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.
More examples of glassfish persistence
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
- Sahoo - You mention the use of dependency injection by annotation in an application client, and in particular the static context in which the main method is run. Could you expand on this. It is very hard to find a definitive statement on this subject; including the EJB and persistence JSR 220 documents. I have an application client composed of a number of classes. One class has an @EJB annotation which fails (java.lang.NullPointerException) if the class is instantiated by another class, but works if a main method is added to the class to instantiate it directly. Whether the annotation uses the static modifier or not makes no difference. Best Regards Graham Robbins
Posted by: grahamrobbins on March 26, 2007 at 08:21 AM
-
Hi Graham,
1. Rules for Injection in application clients is described in section #5.2.3 of the Java EE 5 Platform Specification.
2. I am not surprised to know that you got a NullPointerException when you used @EJB in a class which is not the Main-Class. Only managed classes can use dependency injection facility. For an application client, only the class designated as Main-Class using MANIFEST.MF file is managed class, hence only that class can use dependency injection; all other classes must not use dependency injection.
3. Since the application client container does not actually instantiate your Main-Class, the injected field/method must be static.
Hope this clarifies your doubt. Feel free to send mails to users@glassfish.dev.java.net.
Thanks,
Sahoo
Posted by: ss141213 on March 26, 2007 at 08:40 AM
-
- Sahoo - It is funny how writing things out helps to clear things up! The behaviour is quite clear. We are in an application client. If we are in a class with the main method, then we can use dependency injection by annotation, if we are in any other class (without the main method) then we must use the javax.naming.Context.lookup() method.
In fact Netbeans (5.5) knows this. If we use the 'Call Enterprise Bean' menu item, the appropriate code is inserted: the annotation if we are in the class with the main method, the lookup() if not. It has puzzled me for a long time why Netbeans sometimes gave me one thing, sometimes the other.
I assume that the EE container for application clients is only involved in resource injection at the startup of the application, and not therefter.
Thanks for listening!
Graham Robbins.
Posted by: grahamrobbins on March 26, 2007 at 09:05 AM
-
Oh sorry. I see your answer got there before my second comment. Graham
Posted by: grahamrobbins on March 26, 2007 at 09:06 AM
-
Hi Sahoo,
After reading your statement "Since Application Client Container is not required to support JTA, we can not use JTA entity managers in this example.", I went back to the Java EE 5 specs to get more information.
Is it correct that Glassfish actually supports JTA for Java clients?
Cheers,
Olivier
Posted by: oliechti on November 20, 2007 at 08:29 AM
-
Yes, GlassFish goes beyond the spec requirements, and supports JTA in application client container.
Sahoo
Posted by: ss141213 on November 20, 2007 at 08:45 AM
-
Thank you for the clarification. I am trying to do use it, but have some problems (see http://forums.java.net/jive/thread.jspa?messageID=246736).
Cheers,
Olivier
Posted by: oliechti on November 22, 2007 at 01:27 AM
|