|
|
||
Sahoo's BlogDecember 2005 ArchivesDon'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 {
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 Container Managed Entity Manager @PersistenceContext(name="persistence/LogicalName", unitName="ActualPUNameAsItAppearsInPersistence.xml") 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> Now do a JNDI lookup in your code as shown below: public class RegistrationServlet extends HttpServlet {
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 {
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 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 glassfish persistence. Using Java Persistence API in Java EE Platform - Part IIPosted 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? Software Requirements Structure of the ear file : The final ear looks like this: lib/entities.jar Point to note here are: 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.
Step #1: Write entity bean UserCredential.java Points to note about this entity bean are: 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 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 Step #3: Write UserCredentialManagerBean.java Points to note about this EJB 3 style stateless session bean are: 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 @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: @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: 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 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. 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 glassfish glassfish persistence persistence An annotation processor to update your persistence.xml during javacPosted 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 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 How to 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? 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: Here is a simple convention (rule you may say) followed in Java EE platform from early days: 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:
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: public class RegistrationServlet extends HttpServlet {
Exception Details: Why this exception occurs? What is the fix? public class RegistrationServlet extends HttpServlet {
Comparison with equivalent code in a Session Bean @Stateless Let's analyse the differences between ejb and servlet code: Introduction to using Java Persistence API in a web application in Java EE environmentPosted 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. What is the example? Requirements Detailed Steps Step #1: Write entity bean UserCredential.java Points to note about this entity bean are: 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 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 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 Step #3: Write LoginServlet.java Points to note about this servlet are: @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 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: 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 Step #7: Build using build.xml This is a very simple build.xml just to demonstrate the compilation and packaging process. As you can see, to compile only library needed is javaee.jar which contains the Java EE 5 platform APIs. 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: 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 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: glassfish persistence | ||
|
|