Thursday, 20 August 2009

JPA Entity instances in the surgery



1. Introduction

This article focuses on the JPA entities state after applied CRUD operations. It also explains the real effect and the consequences of the CASCADE definition in the relationships between JPA entities.

2. Entity Instance’s Life Cycle

new entity instance has no persistent identity, and is not yet associated with a persistence context.
managed entity instance has a persistent identity that is currently associated with a persistence context.
detached entity instance has a persistent identity that is not (or no longer) associated with a persistence context.
removed entity instance has with a persistent identity, associated with a persistence context, that is scheduled for removal from the database.






3. Persisting an Entity Instance


A new entity instance becomes both managed and persistent by invoking the persist method on it or by cascading the persist operation.
The semantics of the persist operation, applied to an entity X are as follows:


• If X is a new entity, it becomes managed. The entity X will be entered into the database at either before transaction commit or as a result of the flush operation.


• If X is a preexisting managed entity, it is ignored by the persist operation. However, the persist operation is cascaded to entities referenced by X, if the relationships from X to these other entities is annotated with the cascade=PERSIST or cascade=ALL annotation element value or specified with the equivalent XML descriptor element.


• If X is a removed entity, it becomes managed.


• If X is a detached object, the EntityExistsException may be thrown when the persist operation is invoked, or the EntityExistsException or another PersistenceException may be thrown at flush or commit time.


• For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade=ALL, the persist operation is applied to Y.


4. Removal


A managed entity instance becomes removed by invoking the remove method on it or by cascading the remove operation.
The semantics of the remove operation, applied to an entity X are as follows:


• If X is a new entity, it is ignored by the remove operation. However, the remove operation is cascaded to entities referenced by X, if the relationship from X to these other entities is annotated with the cascade=REMOVE or cascade=ALL annotation element value.


• If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities is annotated with the cascade=REMOVE or cascade=ALL annotation element value.


• If X is a detached entity, an IllegalArgumentException will be thrown by the remove operation (or the transaction commit will fail).


• If X is a removed entity, it is ignored by the remove operation.


• A removed entity X will be removed from the database at or before transaction commit or as a result of the flush operation.


5. Synchronization to the Database


The state of persistent entities is synchronized to the database at transaction commit. This synchronization involving writing to the database any updates to persistent entities and their relationships as specified above.


An update to the state of an entity includes both the assignment of a new value to a persistent property or field of the entity as well as the modification of a mutable value of a persistent property or field.


Synchronization to the database does not involve a refresh of any managed entities unless the refresh operation is explicitly invoked on those entities.
The persistence provider runtime is permitted to perform synchronization to the database at other times as well when a transaction is active. The flush method can be used by the application to force synchronization.


It applies to entities associated with the persistence context.
The semantics of the flush operation, applied to an entity X are as follows:


• If X is a managed entity, it is synchronized to the database.


• For all entities Y referenced by a relationship from X, if the relationship to Y has been annotated with the cascade element value cascade=PERSIST or cascade= ALL, the persist operation is applied to Y.


• For any entity Y referenced by a relationship from X, where the relationship to Y has not been annotated with the cascade element value cascade=PERSIST or cascade= ALL:


• If Y is new or removed, an IllegalStateException will be thrown by the flush operation (and the transaction rolled back) or the transaction commit will fail.


• If Y is detached, the semantics depend upon the ownership of the relationship. If X owns  the relationship, any changes  to the relationship are synchronized with the database; otherwise, if Y owns the relationships, the behavior is  undefined.


• If X is a removed entity, it is removed from the database. No cascade options are relevant.


6. Detached Entities


A detached entity may result from:
·          transaction commit if a transaction-scoped container-managed entity manager is used
·          transaction rollback
·          clearing the persistence context
·          closing an entity manager
·          serializing an entity or otherwise passing an entity by value—e.g., to a separate application tier, through a remote interface, etc.


Detached entity instances continue to live outside of the persistence context in which they were persisted or retrieved, and their state is no longer guaranteed to be synchronized with the database state.


The application may access the available state of available detached entity instances after the persistence context ends. The available state includes:


• Any persistent field or property not marked fetch=LAZY


• Any persistent field or property that was accessed by the application


If the persistent field or property is an association, the available state of an associated instance may only be safely accessed if the associated instance is available. The available instances include:


• Any entity instance retrieved using find().


• Any entity instances retrieved using a query or explicitly requested in a FETCH JOIN clause.


• Any entity instance for which an instance variable holding non-primary-key persistent state was accessed by the application.


• Any entity instance that may be reached from another available instance by navigating associations marked fetch=EAGER.


7. Merging Detached Entity State


The merge operation allows for the propagation of state from detached entities onto persistent entities managed by the EntityManager.
The semantics of the merge operation applied to an entity X are as follows:


• If X is a detached entity, the state of X is copied onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.


• If X is a new entity instance, a new managed entity instance X' is created and the state of X is copied into the new managed entity instance X'.


• If X is a removed entity instance, an IllegalArgumentException will be thrown by the merge operation (or the transaction commit will fail).


• If X is a managed entity, it is ignored by the merge operation, however, the merge operation is cascaded to entities referenced by relationships from X if these relationships have been annotated with the cascade element value cascade=MERGE or cascade=ALL annotation.


• For all entities Y referenced by relationships from X having the cascade element value cascade=MERGE or cascade=ALL, Y is merged recursively as Y'. For all such Y referenced by X, X' is set to reference Y'. (Note that if X is managed then X is the same object as X'.)


• If X is an entity merged to X', with a reference to another entity Y, where cascade=MERGE or cascade=ALL is not specified, then navigation of the same association from X' yields a reference to a managed object Y' with the same persistent identity as Y.


8. Detached Entities and Lazy Loading


Serializing entities and merging those entities back into a persistence context may not be interoperable across vendors when lazy properties or fields and/or relationships are used.
A vendor is required to support the serialization and subsequent deserialization and merging of detached entity instances (which may contain lazy properties or fields and/or relationships that have not been fetched) back into a separate JVM instance of that vendor's runtime, where both runtime instances have access to the entity classes and any required vendor persistence implementation classes.


When interoperability across vendors is required, the application must not use lazy loading.


9. Managed Instances


It is the responsibility of the application to insure that an instance is managed in only a single persistence context. The behavior is undefined if the same Java instance is made managed in more than one persistence context.













Thursday, 13 August 2009

JPA: Digging beyond the entities.



1. Introduction



The idea behind this article is to summarize a set of important concepts related to the Java Persistence API. I am not trying to reinvent the wheel writing something from the scratch. Therefore the text is based on the JSR 220.
2. JPA Concepts
Entities are managed by the entity manager. The entity manager is represented by javax.persistence.EntityManager instances. Each EntityManager instance is associated with a persistence context. A persistence context defines the scope under which particular entity instances are created, persisted, and removed.
A persistence context is a set of managed entity instances that exist in a particular data store. The EntityManager interface defines the methods that are used to interact with the persistence context.
The EntityManager API creates and removes persistent entity instances, finds entities by the entity’s primary key, and allows queries to be run on entities.
Until an entity manager is used, the entity is nothing more than a regular (non-persistent) Java object.
When an entity manager obtains a reference to an entity, either by having it explicitly passed in or because it was read from the database, that object is said to be managed by the entity manager. The set of managed entity instances within an entity manager at any given time is called its persistence context. Only one Java instance with the same persistent identity may exist in a persistence context at any time.
Entity managers are configured to be able to persist or manage specific types of objects, read and write to a given database, and be implemented by a particular persistence provider. It is the provider that supplies the backing implementation engine for the entire Java Persistence API, from the EntityManager through to Query implementation and SQL generation.
All entity managers come from factories of type EntityManagerFactory. The configuration for an entity manager is bound to the EntityManagerFactory that created it, but it is defined separately as a persistence unit. A persistence unit dictates either implicitly or explicitly the settings and entity classes used by all entity managers obtained from the unique EntityManagerFactory instance bound to that persistence unit. There is, therefore, a one-to-one correspondence between a persistence unit and its concrete EntityManagerFactory.




3. Container-managed entity manager
With a container-managed entity manager, an EntityManager instance’s persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction Architecture (JTA) transaction.
A container-managed entity manager is obtained by the application either using injection
@PersitenceContext EntityManager em;




or using JNDI lookup
@Stateless
@PersistenceContext(name=”OrderEM”)
Public class MySessionBean implements MyInterface {
@Resource SessionContext ctx;
Public void doSomething(){
EntityManager em = (EntityManager) ctx.lookup(“OrderEM”);
}
}
  • Container-managed Transaction-scoped Persistence Context
A new persistence context begins when the container-managed entity manager is invoked in the scope of an active JTA transaction, and there is no current persistence context already associated with the JTA transaction. The persistence context is created and then associated with the JTA transaction.
The persistence context ends when the associated JTA transaction commits or rolls back, and all entities that were managed by the EntityManager become detached.
If the entity manager is invoked outside the scope of a transaction, any entities loaded from the database will immediately become detached at the end of the method call.

Case 1
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceContext
EntityManager em;
public Order getOrder(Long id) {
return em.find(Order.class, id);
}
public Product getProduct(String name) {
return (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(Order order, Product product, int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
}
  • Container-managed Extended Persistence Context
A Container-managed extended persistence context can only be initiated within the scope of a stateful session bean. It exists from the point at which the stateful session bean that declares a dependency on an entity manager of type PersistentContextType.EXTENDED is created, and is said to be bound to the stateful session bean.
The persistence context is closed by the container when @Remove method of the stateful session bean completes (or the stateful session bean instance is otherwise destroyed).
Case 1



@
Stateful
@Transaction(REQUIRES_NEW)
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceContext(type = EXTENDED)
EntityManager em;
private Order order;
private Product product;
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
return li;
}
}

4. Application-managed entity manager

With application-managed entity managers, on the other hand, the persistence context is not propagated to application components, and the life cycle of EntityManager instances is managed by the application.
Application-managed entity managers are used when applications need to access a persistence context that is not propagated with the JTA transaction across EntityManager instances in a particular persistence unit. In this case, each EntityManager creates a new, isolated persistence context. The EntityManager, and its associated persistence context, is created and destroyed explicitly by the application.
Applications create EntityManager instances in this case by using the createEntityManager method of javax.persistence.EntityManagerFactory.
To obtain an entity manager factory in a Java EE Container either using injection


@PersistenceUnit
EntityManagerFactory emf;


To obtain an entity manager factory in a Java SE Container:

EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory(“Order”);
EntityManager em = emf.createEntityManager();

  • Application-managed persistent context
When an application-managed entity manager is used, the application interacts directly with the persistence provider's entity manager factory to manage the entity manager lifecycle and to obtain and destroy persistence contexts.
All such application-managed persistence contexts are extended in scope, and may span multiple transactions.
The EntityManager close and isOpen methods are used to manage the lifecycle of an application-managed entity manager and its associated persistence context.
The EntityManager.close method closes an entity manager to release its persistence context and other resources. If the close method is invoked when a transaction is active, the persistence context remains managed until the transaction completes.
The extended persistence context exists from the point at which the entity manager has been created using EntityManagerFactory.createEntityManager until the entity manager is closed by means of EntityManager.close. The extended persistence context obtained from the application-managed entity manager is a stand-alone persistence context—it is not propagated with the transaction.
When a JTA application-managed entity manager is used, if the entity manager is created outside the scope of the current JTA transaction, it is the responsibility of the application to associate the entity manager with the transaction (if desired) by calling EntityManager.joinTransaction.
Case 1 - Application-managed Persistence Context used in Stateles Session Bean




/*
* Container-managed transaction demarcation is used.
* Session bean creates and closes an entity manager in
* each business method.
*/
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
public Order getOrder(Long id) {
EntityManager em = emf.createEntityManager();
Order order = (Order) em.find(Order.class, id);
em.close();
return order;
}
public Product getProduct() {
EntityManager em = emf.createEntityManager();
Product product = (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
em.close();
return product;
}
public LineItem createLineItem(Order order, Product product, int quantity) {
EntityManager em = emf.createEntityManager();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
em.close();
return li; // remains managed until JTA transaction ends
}
}

Case 2 - Application-managed Persistence Context used in Stateless Session Bean

/*
* Container-managed transaction demarcation is used.
* Session bean creates entity manager in PostConstruct
* method and clears persistence context at the end of each
* business method.
*/
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct
public void init()
em = emf.createEntityManager();
}
public Order getOrder(Long id) {
Order order = (Order)em.find(Order.class, id);
em.clear(); // entities are detached
return order;
}
public Product getProduct() {
Product product = (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
em.clear();
return product;
}
public LineItem createLineItem(Order order, Product product, int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
// persistence context is flushed to database;
// all updates will be committed to database on tx commit
em.flush();
// entities in persistence context are detached
em.clear();
return li;
}
@PreDestroy
public void destroy()
em.close();
}
}

Case 3 - Application-managed Persistence Context used in Stateful Session Bean


//Container-managed transaction demarcation is used
@Stateful
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
private Order order;
private Product product;
@PostConstruct
public void init() {
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
return li;
}
@Remove
public void destroy() {
em.close();
}
}

Case 4 - Application-managed Persistence Context with Resource Transaction
// Usage in an ordinary Java class
public class ShoppingImpl {
private EntityManager em;
private EntityManagerFactory emf;
private Order order;
private Product product;
public ShoppingCart() {
emf = Persistence.createEntityManagerFactory("orderMgt");
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.getTransaction().begin();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.getTransaction().commit();
return li;
}
public void destroy() {
em.close();
emf.close();
}
}
5. Controlling Transactions

Depending on the transactional type of the entity manager, transactions involving EntityManager operations may be controlled either through JTA (JTA entity manager) or through use of the resource-local EntityTransaction API (resource-local entity manager), which is mapped to a resource transaction over the resource that underlies the entities managed by the entity manager.

The EntityTransaction interface is used to control resource transactions on resource-local entity managers. The EntityManager.getTransaction() method returns the EntityTransaction interface.
When a resource-local entity manager is used, and the persistence provider runtime throws an exception defined to cause transaction rollback, it must mark the transaction for rollback.
If the EntityTransaction.commit operation fails, the persistence provider must roll back the transaction.

A container-managed entity manager must be a JTA entity manager. JTA entity managers are only specified for use in Java EE containers.
An application-managed entity manager may be either a JTA entity manager or a resource-local entity manager.
An entity manager is defined to be of a given transactional type—either JTA or resource-local—at the time its underlying entity manager factory is configured and created.

Both JTA entity managers and resource-local entity managers are required to be supported in Java EE web containers and EJB containers.Within an EJB environment, a JTA entity manager is typically used.
In general, in Java SE environments only resource-local entity managers are supported.


Example
The following example illustrates the creation of an entity manager factory in a Java SE environment, and its use in creating and using a resource-local entity manager.
import javax.persistence.*;
public class PasswordChanger {
public static void main (String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Order");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
User user = (User)em.createQuery("SELECT u FROM User u WHERE u.name=:name AND u.pass=:pass")
.setParameter("name", args[0])
.setParameter("pass", args[1])
.getSingleResult();
if (user!=null) {
user.setPassword(args[2]);
}
em.getTransaction().commit();
em.close();
emf.close ();
}
}