The Source for Java Technology Collaboration
User: Password:



Sahoo's Blog

December 2005 Archives


Don't use @PersistenceContext in a web app...

Posted by ss141213 on December 19, 2005 at 12:18 PM | Permalink | Comments (9)

I wrote an example web application that uses Java Persistence API. My servlet code looked like this:

public class RegistrationServlet extends HttpServlet {
// inject default EntityManager
@javax.persistence.PersistenceContext private EntityManager em;
@Resource private UserTransaction utx;
public void service ( HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
...
utx.begin();
em.persist(credential);
utx.commit();
...
}
...
}

This code worked, but only by chance. I did not realize that I have committed a horrible mistake in my servlet code. As the servlet spec suggests, unless explicitly mentioned in the deployment descriptor (web.xml) as SingleThreadModel, a single servlet instance by default can be shared to serve multiple requests concurrently. i.e. multiple threads can simultaneously enter the service() method of our servlet because we have not marked the service() as synchronized. As a result multiple threads will share the same PersistenceContext object via the instance variable em. A persistence context is not required to be thread safe as per the spec and is typically designed not to be used concurrently. Because the behavior is timing dependent and I had a tiny example, I did not see this issue during testing.

What is the fix

If we can't use @PersistenceContext to inject an EntityManager, what is the fix? The fix is to either
use @PersistenceUnit to inject an EntityManagerFactory and use it to get hold of an EntityManager,
or
declare a dependency on an EntityManager and use JNDI to look it up.
The former one is called application managed entity manager because application manages the life cycle (by calling EntityManagerFactory.create & EntityManager.close) where as the later one is called container managed entity manager because container manages life cycle. More discussion on differences between container managed vs. application managed will be done in a later article. Let's discuss the fix using both the approaches. Let's discuss each approach using code samples.

Container Managed Entity Manager
There are a couple of ways to use JNDI lookup of entity manager:
a) via annotation:

@PersistenceContext(name="persistence/LogicalName", unitName="ActualPUNameAsItAppearsInPersistence.xml")
public class RegistrationServlet extends HttpServlet {
@Resource private UserTransaction utx;
public void service ( HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
Context envCtx = InitialContext().lookup("java:comp/env");
EntityManager em = (EntityManager) envCtx.lookup("persistence/LogicalName");
...
utx.begin();
em.persist(credential);
utx.commit();
...
}
...
}

Note that there is no injection going on here since the annotation @PersistenceContext appears at the class level. This is an alternative to declaring the persistence context dependency via a persistence-context-ref in web.xml as discussed below (in option #b).

b) via persistence-context-ref in web.xml

In web.xml, add an element like this:

 < persistence-context-ref>
< persistence-context-ref-name>
persistence/LogicalName
</persistence-context-ref>
< persistence-unit-name>
ActualPUNameAsItAppearsInPersistence.xml
</persistence-unit-name>
</persistence-context-ref>

Now do a JNDI lookup in your code as shown below:

public class RegistrationServlet extends HttpServlet {
@Resource private UserTransaction utx;
public void service ( HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
Context envCtx = InitialContext().lookup("java:comp/env");
EntityManager em = (EntityManager) envCtx.lookup("persistence/LogicalName");
...
utx.begin();
em.persist(credential);
utx.commit();
...
}
...
}

While using container managed entity manager (whether option #a or #b is used), we did not call em.close() because container is managing the life cycle of underlying persistence context. We also did not have to call utx.rollback() because web container would automatically rollback a transaction at the end of http request processing if servlet does not end the tx.

Application Managed Entity Manager

public class RegistrationServlet extends HttpServlet {
// inject EntityManagerfactory
@javax.persistence.PersistenceUnit private EntityManagerFactory emf;
@Resource private UserTransaction utx;
public void service ( HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
EntityManager em = emf.createEntityManager();
try {
...
utx.begin();
em.persist(credential);
utx.commit();
...
} catch (Exception e){
try {
utx.rollback();
} catch (Exception e) {}
} finally {
em.close();
}
}
...
}

See we call close() to close the EntityManager. More over note the use of try catch finally block. Since em.close() can not be called as long as the associated transaction is complete either by calling commit() or rollback(), we have to write those try catch finally.

Is it mentioned any where in the spec?

In Transaction Management chapter, section #4.2.3 of Java EE 5 proposed final draft spec, it is mentioned that:

In web components not implementing SingleThreadModel, transactional resource
objects should not be stored in class instance fields, and should be acquired
and released within the same invocation of the service method.

If you want to draw an analogy with JDBC world then EntityManager is like a Connection, where as EntityManagerFactory is like a DataSource. So EntityManager (or a PersistenceContext) which is a transactional resource should not be stored in a instance field and hence should not be injecte into a web app that does not implement SingleThreadModel.EntityManagerFactory is thread safe, so it can be injected into the servlet.

What is the performance over head?

Creation of a EntityManagerFactory is typically a costly operation. But creation of EntityManager is not. So creating an EntityManager is inside service() does not have negative impact on performance.

What about thread safety of UserTransaction?

If you see the code above, it still injects a UserTransaction object and stores in an instance field. That is not issue because it is a stateless object and can be shared across multiple threads. Looking at the javadocs for UserTransaction, it is clear that it by itself does not represent the transaction object, instead it is an interface to the underlying transaction manager to begin a new transaction and associate that with current thread; and end a transaction associated with current thread.

More articles about .



Using Java Persistence API in Java EE Platform - Part II

Posted by ss141213 on December 15, 2005 at 08:59 AM | Permalink | Comments (17)

The Java Persistence API is the standard API for the management of persistence and object/relational mapping in Java EE 5 platform. Every Java EE 5 compatible application server will support this API. Earlier I had written about how to use Java Persistence API in a web application. This time I shall extend the example to include EJBs and application client so that we have a multi-tier (web->ejb->db and appclient->ejb->db) Java EE app. The focus of this exercise is to show how simple it is to develop such complex multi-tier Java EE application in a portable way. We will see how to package such an application so that it is not only portable, but also efficient. It uses the library directory facility to package common classes. In the process we shall see various injections like @EJB and @PersistenceContext in use. Like last time, I will not use any kind of IDE because Java EE 5 is Easy to Use. More over IDEs tend to do things behind the screen and that hampers learning. Because of the walkthrough nature of this article, it's to be a long one, but don't get overwhelmed by the size! At each critical step , I shall try to explain why certain things are done the way they are. If you are impatient, you can download the complete sample, unzip and run 'ant deploy' to see the sample in action. The actual steps are very simple as you can see from this README.

What is the example?
The ear file has three modules: viz: a web module, an ejb module and an appclient module. The web module has a login page and a new user registration page. They internally use two servlets. The servlets talk to the ejb which uses Java Persistence API to access user details that are stored in a database. The appclient module also talks to the ejb module. The complete sample is available here.

Software Requirements
An implementation of the Java Persistence API is being done in glassfish project. You can download the latest promoted build and try out the sample yourself. Although I am using glassfish to build and run this sample, atmost you have to do some very minor changes 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 it uses vendor extension section of persistence.xml to do this.

Structure of the ear file :

The final ear looks like this:

lib/entities.jar
lib/ejb-interfaces.jar
ejbs.jar
web-app2.war
appclient.jar

Point to note here are:
1) There is no application.xml in this ear file, as in Java EE 5, application.xml has become optional.

2) For sake of clarity, entity beans are packaged in entities.jar and EJB interface classes are packaged in ejb-interfaces.jar. All other modules depend on these two jar files. So sharing them is a challenge.

3) It uses lib directory to share entities.jar and ejb-interfaces.jar with other modules. lib directory is a special directory introduced in Java EE 5. By default its name is lib, but it can be overridden by using application.xml. The intended use is to place library jar files in this directory so that they can be made available to all other modules in the ear file without having to use Class-Path manifest attribute as explained in Bundled Optional Package Support in Java EE 5 platform spec chapter #8. So our entities.jar and ejb-interfaces.jar are automatically available to ejbs.jar, web-app2.war and appclient.jar. This way there is no duplication of classes in the ear.

Since entities.jar is placed in lib directory, not only is it available to all other module's class loader, but also the Persistence Unit defined in this jar file is visible to all other modules.

4) ejbs.jar only contains the session bean classes. There is no ejb-jar.xml inside it. Also note that ejbs.jar does not bundle entities.jar, yet it uses the persistence unit which is defined in lib/entities.jar. This is allowed as per the sharing rules of persistence units.

5) web-app2.war contains the servlet classes and html files.

6) In addition to example.client.Main.class appclient.jar contains a META-INF/MANIFEST.MF file.


Detailed Steps

Step #1: Write entity bean UserCredential.java

Points to note about this entity bean are:
1) This is a Plain Old Java Object (POJO): It does not extend any predefined class, nor does it implement any particular interface other than java.io.Serializable. An entity bean must implement java.io.Serializable interface if it is used in RMI-IIOP (EJB) interface. Since in this example it is being used in the EJB interface, we have to do so.

2) There is no deployment descriptor needed to specify that it is an entity bean. Instead the class has been annotated as @Entity as shown below:

@Entity public class UserCredential implements Serializable.

The persistence provider automatically determines whether we are annotating FIELDs or PROPERTIEs. In this case, we have decided to annotate fields.

3) Every entity bean must have an identity. In our case, it is specified using @Id as below. I have chosen to use @Id because we have a single field primary key. Other annotations like @IdClass, @EmbeddedId are typcally used for composite primary key.

@Id private String name;

4) Also note that we have not used @GeneratedValue along with @Id. When an id field is not annotated with @GeneratedValue, it means that user is responsible for setting the identity. Provider will not set the id field value.

5) Although it is possible to specify exact table name using @Table and column names using @Column for an entity bean, we can rely on the default mapping that the specification defines and yet expect the application to be portable because this default mapping rule is defined by the spec itself. UserCredential bean gets mapped to a table called USERCREDENTIAL, name & password fields get mapped to NAME and PASSWORD columns respectively.

Step #2: Define a persistence unit in persistence.xml

A Persistence Unit (PU) is a logical grouping of a set of related entity beans. A PU also contains configuration details about the entity managers that are going to manage these entity beans. Actually the configuration is applied to an EntityManagerFactory which in turn creates homogeneous EntityManager instances. But this is all taken care of by the container to persistence provider interaction. As a user to define a PU, we just need to write a node in persistence.xml file. 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 other elements/attributes, as the default values are just fine for most applications. e.g. by default the entity manager's transaction type is JTA.

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 UserCredentialManagerBean.java

Points to note about this EJB 3 style stateless session bean are:
1) It is a Plain Old Java Object (POJO): It does not extend any predefined class, nor does it implement any predefined interface. It only implements its own business interface UserCredentialManager.

2) There is no deployment descriptor needed to specify that it is a stateless session bean. Instead the class has been annotated as shown below:

@Stateless @Remote

public class UserCredentialManagerBean implements UserCredentialManager {...

@Remote annotation is required b'cos the business interface UserCredentialManager is neither annotated as @Local nor as @Remote. So by default our session bean would have exposed a local business interface. Since we want the EJB to be accessible from an application client, having only local interface would not work. So we are using @Remote annotation. The other option would have been to have both local and remote interface, but let's postpone that discussion to some other time.

3) It talks to database using EntityManager API. It declares dependency on an EntityManager using @PersistenceContext annotation:

@PersistenceContext private EntityManager em;

Since there is only one Persistence Unit(PU) defined in the scope of this ejb, there is no need to specify the unitName in @PersistenceContext. Please also note that an injected variable in a servlet or ejb must not be declared static or final. In our example, em follows this rule as well.

4) The business method "createUser" creates a new object in the database by one line code:

em.persist(uc);

The business method "authenticate" uses the following code:

UserCredential uc = em.find(UserCredential.class, name);

to locates a matching UserCredential object in the database.

The business method "removeUser" first locates the named user credential and then calls

em.remove(uc);

to remove it from the database.

Unlike em.find(), em.remove() and em.persist() require an active transaction context. But as you can see none of the EJB methods starts a transaction. That is because by default the transaction management type is CONTAINER and the transaction attribute of business method is REQUIRED. So ejb container takes care of transaction management! This is unlike web container as discussed here.

There is no need to write an ejb-jar.xml because a Java EE 5 compatible container can identify ejbs.jar as an EJB module because it contains a class that is annotated as Stateless.

Step #4: Write LoginServlet.java

Points to note about this servlet are:
1) It declares dependency on the EJB using @EJB annotation:

@EJB private UserCredentialManager ucm;

Since there is only one bean that implements this business interface, there is no need to specify any of the attributes of @EJB.

2) When user tries to login using a user name and password, it calls the EJB method to authenticate as shown below:

ucm.authenticate(name, password);

Step #5: Write RegistrationServlet.java

Note it also uses an injected EJB. It also calls the createUser EJB method to create a new user.

Both the servlets do not do any transaction management, because that is handled by the EJB layer. They also do not explicitly depend on the Java Persistence API.

Step #6: Write web.xml

We are having to write an web.xml only because we have to define a couple of request path mappings to servlets.

Step #7: Write a couple of html files
Refer to login.html and registration.html inside the sample zip file. They are used to call the servlets.

Step #8: Write an appclient Main.java

Points to note about this appclient are that:

1) It declares dependency on the EJB using @EJB as shown below:

@EJB private static UserCredentialManager ucm;

Also note that, the field ucm is static. That's because unlike EJB or Servlets, injected fields in an application client must be static as Application Client Container (ACC) does not instantiate the class, instead it calls the static main().

Since in this ear file, there is only one session bean that implements UserCredentialManager interface, there is no need to specify any other attributes of the EJB.

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() so that ACC knows which is the main class to look for injected fields and main(). Thsi file gets bundled in appclient.jar as META-INF/MANIFEST.MF file.

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 #9: Build using build.xml

This is a very simple build.xml just to demonstrate the compilation and packaging process.
The build targets are:
build -- This builds an ear file called blog5.ear.
clean -- cleans
verify -- verify uses a tool called verifier that checks compliance of the application against Java EE spec.
deploy -- deploys the ear file
undeploy -- undeploys the ear file
The last three targets are specific to Sun Java System Application Server 9 PE which is implementing Java EE 5 spec.

As you can see, to compile the sources, only library needed is javaee.jar which contains the Java EE 5 platform APIs.

The deploy target in build.xml uses a feature called Java2DB which can automatically create the tables during deployment. This is specific to Sun's app server, but such features are supported in many other commercial applications servers as well.

Hope you found this example useful.

More blogs about



An annotation processor to update your persistence.xml during javac

Posted by ss141213 on December 13, 2005 at 02:44 PM | Permalink | Comments (1)

When Java Persistence API is used in a managed environment (like Java EE container), there is often a deployment step and a notion of deployable module (an ear/war/jar) that represents the boundary of an application. During deployment container/persistence provider can discover managed persistence classes by introspecting .class files bundled in the application. But when Java Persistence API is used in Java SE environment, there is no such predefined deployment step, nor is there any deployable module. So a persistence provider does not know what are all the classes to introspect. Hence the spec requires users to specify the list of managed persistence classes in persistence.xml. A managed persistence class is a class that is either an Entity or Embeddable or EmbeddableSuperclass.

In this article, I shall show how to write an Annotation Processor that can be used along with J2SE's Annotation Processing Tool to automatically generate the list of managed persistence classes and update persistence.xml during compilation of entity source code. In the process I will also show how to use JAXB to read and write XML. I suggest you read this if you are not familiar with apt. The complete source code along with a build script is available here. There is also a README that tells you how to build and use the tool.

Overview of the source code:

1. AnnotationProcessorFactory: ListPersistenceClassApf.java

This is the entry point. It implements AnnotationProcessorFactory interface.

2. AnnotationProcessor: ListPersistenceClassAp.java
This is the real annotation processor. It implements AnnotationProcessor interface. ListPersistenceClassApf instantiates this class and hands over the declarations for annotation processing.

3. service provider configuration file: META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory

apt is a generic tool that comes with Sun's JDK. It does not know about our custom annotation processor factory. So it has to be told about our annotation processor factory. It can be done in a couple of ways: passing -factory option while invoking apt or by using service provider configuration file. I am using the later approach.

4. Marshalling and unmarshalling of persistence.xml XMLReaderWriter.java

As you can see from this source code, I am using JAXB 2.0 RI to read and write persistence.xml. The reason I use JAXB is because it generates the code that is responsible for reading and writing XML from a given schema. See the gen-src target in build.xml to see how we generate code using JAXB. Also take a look at the binding.xjb
if you are interested to know how to control code generation.

How to build?
Download latest build of glassfish from here.
set glassfish.home in build.xml and run 'ant build'.

The reason I use glassfish is because it implements Java EE 5 spec, which means both Java Persistence API 1.0 as well as JAXB 2.0.

How to use?
export GLASSFISH_HOME="Wherever you have installed glassfish"
apt -d samples/classes/ -classpath $GLASSFISH_HOME/lib/javaee.jar:$GLASSFISH_HOME/lib/appserv-ws.jar:`pwd`/build/apt.jar -Add=samples/persistence.xml samples/src/sahoo/*.java

See the above command is invoked just like you invoke javac to compile a set of java sources available in samples/src/sahoo/ dir and you directing the compiler to produce the classes in samples/classes dir.
In fact it does what ever javac does + more.
The only non-javac option used here is -Add which is used by our
annotation processor to know the input persistence.xml file location.

The above command picks up Java sources from samples/src dir and
persistence.xml from samples dir. It produces the new persistence.xml
in samples/classes/META-INF dir. It produces the classes in samples/build
directory.

Continue Reading...



Why do I not have to use .par file to bundle my EJB 3.0 entity beans?

Posted by ss141213 on December 06, 2005 at 11:38 PM | Permalink | Comments (7)

Public Review version of the Java Persistence API (JPA) spec suggested a new extension par be used to bundle EJB 3 persistence entity beans. It also suggested a new module type called persistence to be used in application.xml, if user uses an application.xml in their ear file containing persistence entity beans. (Note application.xml is optional starting with Java EE 5.)

Lot of developers still believe that .par is needed. Looking at the comments in theserverside.com to an earlier posted tutorial showing how to use JPA in web application it is very clear that user community do not want a proliferation of extensions used in Java EE platform. Here is a good news:
.par is not needed any more -- take a look at latest XML schema of application.xml posted in project glassfish web site. There is no mention of persistence module type.

Here is a simple convention (rule you may say) followed in Java EE platform from early days:
Any jar-format file that packages classes that can be directly loaded by a class loader ends with a .jar extension. e.g. jar files containing EJB classes, application client classes, utility classes all end with .jar extension (not even .zip). This is precisely why, bundled optional libraries must only be .jar files as mentioned in chapter #8 of the Java EE 5 platform spec available here .

As you can see .ear, .war and .rar do not fall into this category, as they do not package classes directly inside them which are used by a standard class loader. Note that although .war sometimes directly contains classes that are used by an applet, but the applet container is not given the .war file, instead it downloads the classes from the web server.

I must say having this convention prevented introduction of .par file and it is a relief. This kind of convention is also getting into Java SE, because I have heard in Java SE 6 (mustang) there is going to be a facility to specify a directory in the CLASSPATH environment variable and VM will look for all *.jar files in that directory and add it to CLASSPATH automatically.

So if you want to write portable applications, stick to these principles. Sun's next version of application server which is being develped in open sorce project named glassfish does not require any such extensions like .ejb3 or .par.

As a result of this not requiring .par files, the most notable simplification is:
You don't always need an .ear file to use EJB 3 persistece entity beans in Java EE platform. You can bundle them in .war files and deploy .war directly if you are developing such an app. e.g. see tutorial showing how to use JPA in web application. You could even take such a war file and use it in a Java web server, if that supports JPA. You can bundle the entity classes along with ejb classes in an ejb-jar and deploy the ejb-jar directly.


Similarly many developers think EJB 3 session beans have to be packaged in a jar file with extension .ejb3. Let me tell you, that was JBoss specific. I am not up-to-date with recent developments in JBoss, so not sure if they still require this and what are their plans.

Continue Reading...



EntityManager.persist() throws TransactionRequiredException in a servlet?

Posted by ss141213 on December 05, 2005 at 09:37 AM | Permalink | Comments (3)

In my last blog I discussed about using Java Persistence API in a web application. In this article I shall talk about a very common mistake that a web-app developer commits and how to fix it. Java Persistence API is part of Java EE 5 platform which is being reference implemented in open source project called glassfish.

Code that does not work:
Given below is the code snippet of a servlet which uses an entity bean called UserCredential using a container managed EntityManager.

public class RegistrationServlet extends HttpServlet {
// This injects the default persistence unit.
@PersistenceUnit private EntityManagerFactory emf;
public void service (HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
try {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
...
String name = req.getParameter("name");
String password = req.getParameter("password");
UserCredential credential = new UserCredential(name, password);
EntityManager em = emf.getEntityManager(); // container managed em
// em.persist makes the new object as persistent and managed.
em.persist(credential);
out.println("Successfully created the new user. ");
} catch (Exception nse) {
throw new ServletException(nse);
}
}
// other servlet methods like init etc. are omitted for bravity.
}

Exception Details:
When the service() method gets executed, this servlet gets the following exception:
javax.persistence.TransactionRequiredException:
Exception Description: Error marking externally managed transaction for rollback

Why this exception occurs?
If you refer to persist() method in EntityManager.java you can see the javadocs clearly mention that persist throws javax.persistence.TransactionRequiredException if there is no transaction. Since we did not start a transaction in the service() method in servlet before calling em.persist(), the servlet got the exception.

What is the fix?
To fix this, update the servlet code as given below (new code is in bold face letter):

public class RegistrationServlet extends HttpServlet {
// This injects the default persistence unit.
@PersistenceContext private EntityManagerFactory emf;
// This injects a user transaction object.
@Resource private UserTransaction utx;
public void service (HttpServletRequest req , HttpServletResponse resp)
throws ServletException, IOException {
try {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
...
String name = req.getParameter("name");
String password = req.getParameter("password");
// we must begin a tx.
utx.begin();
UserCredential credential = new UserCredential(name, password);
EntityManager em = emf.getEntityManager(); // container managed em
// em.persist makes the new object as persistent and managed.
em.persist(credential);
// commit the transaction,
// b'cos web container rollbacks unfinished tx at the end of request
utx.commit();
out.println("Successfully created the new user. ");
} catch (Exception nse) {
throw new ServletException(nse);
}
}
// other servlet methods like init etc. are omitted for bravity.
}

Comparison with equivalent code in a Session Bean
Let's compare the difference in behavior between a servlet and an ejb.
Given below is a stateless session bean that has a business interface called PasswordManager which has a method of type "void createNewUser(String, String)".

@Stateless
class PasswordManagerBean implements PasswordManager {
@PersistenceContext private EntityManager em;
public void createNewUser(String name, String password) {
UserCredential credential = new UserCredential(name, password);
// em.persist makes the new object as persistent and managed.
em.persist(credential);
}
}

Let's analyse the differences between ejb and servlet code:
Of course ejb code does not have the HttpResponse related code. The other significant difference is that ejb uses @PersistenceContext to get hold of an EntityManager where as the servlet uses @PersistenceUnit to get hold of an EntityManagerFactory and then calls getEntityManager() on the injected EntityManagerFactory to get hold of an EntityManager. The reason why the servlet does not use @persistenceContext is discussed here. That's not the point I am trying to make here. See that the entity creation code and EntityManager interaction code is exacty same as it was in the original servlet code. Yet the servlet gets the exception where as the ejb works. You are wondering why?
For the EJB, default transaction management type is CONTAINER and default transaction attribute for a business method is REQUIRED. So even though we did not specify transaction attributes in our bean class, defaults took over. So even if the business method does not start a transaction, the EJB container starts a transaction if the business method is called in null transaction context and ends it at the end of business method. Hence em.persist() works. For servlet, web container does not implicitly starts a transaction. The web container is only required to roll back a transaction if service() method leaves behind an unfinished transaction.
Hope this helped!
Technorati Tags:
More blogs about glassfish.



Introduction to using Java Persistence API in a web application in Java EE environment

Posted by ss141213 on December 04, 2005 at 03:29 PM | Permalink | Comments (27)

The Java Persistence API is the standard API for the management of persistence and object/relational mapping in Java EE 5 platform. Every Java EE 5 compatible application server will support this API. In this entry I will show how to use this API from a web application in Java EE environment.
Since the public review version of Java Persistence API specification, there have been a number of significant changes about packaging of applications that use Java Persistence API. So I will also show how to package such an application in a portable way. In this exercise, I will not use any kind of IDE because I don't want any magic! This article is going to be a long one because I am trying to explain the steps in detail as well as why certain things are done the way they are. But the steps are very simple as you can see from the README.

What is the example?
It's a web application which has a login page and a new user registration page. It talks to a database where user details are stored. The complete sample is available here. There is a README inside that zip file as well.

Requirements
The Reference Implementation(RI) of the Java Persistence API is being done in glassfish project. You can download the latest promoted build and try out the sample yourself.
Although I am using the RI to build and run this sample, atmost you have to do some very minor changes to persistence.xml and build.xml to make this app build and run in any other application server that supports Java EE 5 specification.

Detailed Steps

Step #1: Write entity bean UserCredential.java

Points to note about this entity bean are:
1) This is a Plain Old Java Object (POJO): It does not extend any predefined class, nor does it implement any particular interface other than java.io.Serializable. An entity bean must implement java.io.Serializable interface if it is used in RMI-IIOP interface. Since in this example, RMI-IIOP is not used, technically this bean does not have to implement this interface. Never-the-less it is a good idea to make an entity bean RMI-IIOP ready, so I have done so.

2) There is no deployment descriptor needed to specify that it is an entity bean. Instead the class has been annotated as @Entity as shown below:

@Entity
public class UserCredential implements java.io.Serializable
.

The persistence provider automatically determines whether we are annotating FIELDs or PROPERTIEs. In this case, we have decided to annotate fields.

3) Every entity bean must have an identity. In our case, it is specified using @Id as below:

@Id private String name;

I have chosen to use @Id because we have a single field primary key. Other annotations like @IdClass, @EmbeddedId are typcally used for composite primary key.

4) Also note that we have not used @GeneratedValue along with @Id. When an id field is not annotated with @GeneratedValue, it means that user is responsible for setting the identity. Provider will not set the id field.

5) Although it is possible to specify exact table name and column names for the entity bean, we can rely on the default mapping that the specification defines. Because of the default mapping rules, UserCredential bean gets mapped to a table called USERCREDENTIAL, name & password fiels get mapped to NAME and PASSWORD columns respectively.

Step #2: Define a persistence unit

A Persistence Unit (PU) is a logical grouping of a set of related entity beans. A PU also contains configuration details about the entity managers that are going to manage these entity beans. Actually the ocnfiguration is applied to an EntityManagerFactory which in turn creates homogenious entity manager instances. To define a PU we need to write a node in persistence.xml file. 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 em1.

2) We need not specify any other elements/attributes, as the default values are just fine for most applications. e.g. by default the entity manager's transaction type is JTA.

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 LoginServlet.java

Points to note about this servlet are:
1) It talks to database using EntityManager API. It declares dependency on an EntityManagerFactory using @PersistenceUnit annotation:

@PersistenceUnit private EntityManagerFactory emf;

Since there is only one Persistence Unit(PU) defined in the scope of the web-app, there is no need to specify the unitName in @PersistenceUnit. Please also note that an injected variable in a servlet or ejb must not be declared static or final. In our example, emf follows this rule as well.

2) Also note that the servlet does not have an instance field of type EntityManager. This is because EntityManager is not thread safe. Since this servlet is not denoted as a SingleThreadModel servlet, one instance of servlet gets shared by mutiple clients and service method of servlet can be called by multiple threads concurrently. So we can't directly inject an EntityManager. Instead we inject an EntityManagerFactory which is thread safe.

3) In the service(), we create an EntityManager using the following code:

EntityManager em = emf.createEntityManager();

We also close the EntityManager in the finally block.

4) When user tries to login using a user name and password, it uses

UserCredential credential = em.find(UserCredential.class, name);

to find a matching UserCredential entity in the database.

5) Since EntityManager.find does not require a transaction to be started, the servlet does not have to begin a transaction before calling em.find().

Step #4: Write RegistrationServlet.java

Note:
1) It uses an injected EntityManagerFactory.

2) It uses

EntityManager.persist()

to create a new entity in the in the database .

3) Since EntityManager.persist() needs to be called in the context of a transaction, this servlet begins a transaction by calling

utx.begin()

and commits the tx before returning.

4) Also note that it uses an injected UserTransaction object as follows:

@Resource private UserTransaction utx;

Unlike EntityManager, UserTransaction is thread safe, so it is OK to inject it into a servlet.

5) Also see how we ensure that when we close the EntityManager there is no active transaction context, otherwise EntityManager.close() will throw an exception.

Step #5: Write web.xml

We are having to write an web.xml only because we have to define a couple of request path mappings to servlets.

Step #6: Write a couple of html files
Refer to login.html and registration.html inside the sample zip file. They are used to call the servlets.

Step #7: Build using build.xml

This is a very simple build.xml just to demonstrate the compilation and packaging process.
The build targets are:
build -- This builds the war file.
clean -- cleans
verify -- verify uses a tool called verifier that checks compliance of the application against Java EE spec.
deploy -- deploys the war file
undeploy -- undeploys the war file
The last three targets are specific to Java EE 5 Reference Implementation (a.k.a. Sun Java System Application Server 9 PE).

As you can see, to compile only library needed is javaee.jar which contains the Java EE 5 platform APIs.
Packaging is done in two steps:

a) build-entities target which compiles only entity beans, copies persistence.xml to output directory and make a jar file called entities.jar. See entities.jar contains persistence.xml in META-INF dir. This jar file is used during compilation of servlets. More over this is also bundled inside the war file's WEB-INF/lib directory.

b) build-web-app1 target which compiles the servlets, copies web.xml and html files to output directories amd makes a war file called web-app1.war. A few points worth noting here are:
in addition to javaee.jar, entities.jar is also used while compiling the servlets.
servlet classes are bundled in WEB-INF/classes directory.
entities.jar is bundled inside WEB-INF/lib directory

Another packaging option is to package META-INF/persistence.xml and entity classes in WEB-INF/classes. But I just feel having a separate jar file with entities in it keeps things clean. It improves reusability.

Step #8: Set up a data source

By default entity manager uses the default pre-configured data source with JNDI name jdbc/__default that glassfish comes with. This data source talks to a Derby database called sun-appserv-samples. Refer to the README where I have listed the command needed to create the tables in Derby. Glassfish has a feature called Java2DB which can autocreate the database schema during deployment, but because of a bug this feature is not currently supported for Derby. Very soon (in a week or so), this bug is going to be fixed. Watch out glassfish EJB 3.0 persistence project page.

Step #9: Run the web-app
Type http://localhost:8080/web-app1/login.html in the browser. Replace localhost & 8080 by host and port as appropriate in your env.

Hope this entry is useful. In the next entry, we will take a step further and write an enterprise application where a web application talks to database using session beans.

Technorati Tags:





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds