text:
Take Notes from Enterprise JavaBeans 3.0
Entity Bean
Entity beans in the Java Persistence 1.0 specification are available only as plain old Java objects (POJOs), and are mapped to tables in a relational database. Unlike other EJB types, entities can be allocated, serialized, and sent across the network like any other POJO.
In Java Persistence, entity beans and the EntityManager do not require an application server. You can use Java Persistence in unit tests and standalone Java applications like you would any other Java library. However, the EJB 3.0 specification does provide additional tight integration with Java Persistence to make it easier to manage persistence services. Other than allowing you to write less code, this integration has additional features that are not available in Java Persistence.
The Entity Bean Class
Entity beans are different from EJB session beans in that they are POJOs. They do not have a remote or local interface and can be accessed only as POJOs.
@Entity @Table(name="CABIN")
class Cabin {@Id @GeneratedValue @Column(name="CABIN_ID") int getId( ) { return id; }}
XML Deployment Descriptors and JAR Files
Entity beans are grouped into a finite set of classes called a persistence unit . There is an EntityManager service that manages a persistence unit, and it must be identified so that it can be referenced in application code. Also, each persistence unit must be associated to a particular database so that the persistence provider knows where, how, and with what kind of database it is interacting. This information is stored in an XML deployment descriptor named persistence.xml and is a required artifact.
The Enterprise Bean Component
Enterprise JavaBeans server-side components come in two fundamentally different types: session beans and message-driven beans. Message-driven beans process messages asynchronously from systems like the JMS, legacy systems, and web services.
Classes and Interfaces
Remote interface
The remote interface defines a session bean's business methods, which can be accessed from applications outside the EJB container: the business methods a bean presents to the outside world to do its work. The remote interface is a plain Java interface. It is tagged with the @Remote annotation to identify that it is a remote interface.
Local interface
The local interface defines a session bean's business methods that can be used by other beans in the same EJB container: the business methods a bean presents to other beans running in the same JVM. It allows beans to interact without the overhead of a distributed object protocol, which improves their performance. The local interface is a plain Java interface. It is tagged with the @Local annotation to identify that it is a local interface.
Endpoint interface
The endpoint interface defines business methods that can be accessed from applications outside the EJB container via SOAP. The endpoint interface is based on Java API for XML-RPC (JAX-RPC) and is designed to adhere to the SOAP and WSDL standards. The endpoint interface is a plain Java interface that is annotated with the @WebService annotation.
Message interface
Message-driven beans implement the message interface, which defines the methods by which messaging systems, such as the JMS, can deliver messages to the bean.
Bean class
The session bean class contains business logic and must have at least one remote, local, or endpoint interface. It usually implements these interfaces, but it is not required to. A bean class may also have more than one interface of a given type. The EJB container usually determines whether a session bean is remote and/or local by the interfaces it implements. The session bean class must also be tagged with the @Stateful or @Stateless annotation so that the EJB container knows what session bean type it is.
The proxy stub, EJB container, and bean instance
When your business logic interacts with a session bean, it is not working directly with instances of the bean class; it is working through the bean's remote or local interface. When you invoke methods on the remote or local interface, the object instance you are using is something called a proxy stub. This proxy stub implements the remote or local interface of the session bean and is responsible for sending your session bean method invocation over the network to your remote EJB container or routing the request to an EJB container that is local in the JVM. The proxy stub can be generated by a precompiler, such as RMI's rmic. Or, as in the case of JBoss, it is dynamically generated at deployment time using the java.lang.reflect.Proxy facilities that come with the JDK.
The proxy stub routes the method invocation to the EJB container on the server (or in the server if it is a local interface). It is the EJB container's job to manage bean class instances as well as security and transaction demarcation. The EJB container has knowledge of the metadata defined as annotations on the bean class or as elements in the XML deployment descriptor. Based on this metadata, it will start a transaction and perform authentication and authorization tasks. It also is responsible for managing the life cycle of the bean instance and routing the request from the proxy to the real bean class instance.
After the EJB container has managed the life cycle of the bean instance, started any transactions, and performed its security checks, it routes the invocation to an actual bean instance.
Modeling Taskflow with Session Beans
Stateful and statelessl session beans
Session beans can be either stateful or stateless. Stateful session beans maintain conversational state when used by a client. Conversational state is not written to a database; it's information that is kept in memory while a client carries on a conversation with an enterprise bean, and it is lost when the conversation ends or the EJB container crashes.
Stateless session beans do not maintain any conversational state. Each method is completely independent and uses only data passed in its parameters. Stateless session beans provide better performance and consume fewer resources than entity and stateful session beans because a few stateless session bean instances can serve hundreds and possibly thousands of clients.
Message-Driven Beans
Java applications or legacy systems that need to access EJB applications can send messages to message-driven beans via JMS. These beans process those messages and perform the required tasks using other entity and session beans.
In EJB 3.0, your code does not have to implement empty callback methods like it does in older versions of the EJB specification. You write code only for those events that you are interested in.
EJBContext is an interface that is implemented by the container and is also part of the bean-container contract. Session beans use a subclass called SessionContext. Message-driven beans use the subclass MessageDriven-Context. These EJBContext types provide the bean with information about its environment: its container, the client using the enterprise bean, and the bean itself. The bean can use this information while processing requests from clients and callback methods from the container.
An enterprise bean's interface with the container also includes a JNDI namespace, called the environment-naming context, which the bean can use to look up the resources it needs (including other beans).
There are three basic kinds of beans: entity, session, and message-driven.
The EJB proxy stub is a conceptual construct that delegates method invocations to session beans from the client and helps the container manage the enterprise bean at runtime. The clients of session beans do not interact with the instances of the session bean class directly. Instead, the client software interacts with the proxy stub. The proxy stub implements the remote and/or local interface and expands the bean class's functionality. Entity beans are created in the same way as any other Java object and are managed by the EntityManager service.
Beans interact with their containers through the well-defined bean-container contract. This contract provides callback methods, the EJBContext , and the JNDI environment-naming context. The callback methods notify the bean class that it is involved in a life cycle event. The EJBContext and JNDI environment-naming context provide the bean instance with information about its environment.
Resource Management and Primary Services
EJB servers support six primary services: concurrency, transaction management, persistence, object distribution, naming, and security. These services provide the kind of infrastructure that is necessary for a successful three-tier system. EJB also supports two additional services: asynchronous messaging and a timer service.
Resource Management
EJB explicitly supports two mechanisms that make it easier to manage large numbers of beans at runtime: instance pooling and activation. In addition, EJB supports the use of the Java EE Connector Architecture (Java EE Connectors) for managing resource connections.
Instance Pooling
Instance pooling is possible because clients never access beans directly.
The stateless session bean life cycle
Because a stateless session bean does not maintain any state between method invocations, every method invocation operates independently, performing its task without relying on instance variables. This means that any stateless session instance can service requests for any EJB object of the proper type. The container can therefore swap bean instances in and out between method invocations.
Normally To set up an instance pool, the EJB container creates several instances of a bean class and then holds on to them until they are needed. As clients make business-method requests, bean instances from the pool are assigned to the EJB requests associated with the clients. After the request is complete, the EJB object doesn't need the instance anymore and it's returned to the instance pool. An EJB server maintains instance pools for every type of stateless session bean deployed. Every instance in an instance pool is equivalentthey are all treated equally. Instances are selected arbitrarily from the instance pool and are assigned to EJB requests as needed.
When a bean instance is finished servicing a request for an EJB object, it is immediately made available to any other EJB object that needs it. This allows fewer stateless session instances to service more requests, which decreases resource consumption and improves performance.
Message-driven beans and instance pooling
Message-driven beans, like stateless session beans, do not maintain state specific to a client request, which makes them excellent candidates for instance pooling.
The Activation Mechanism
Stateful session beans use activation to conserve resources. When an EJB server needs to conserve resources, it can evict stateful session beans from memory. When a bean is evicted, its conversational state is serialized to secondary storage. When a client invokes a method on the EJB object, a new stateful session bean instance is instantiated and populated with the state from the initial bean.
Passivation is the act of disassociating a stateful bean instance from its EJB object and saving its state. Passivation requires that the bean instance's state be held relative to its EJB object. After the bean has been passivated, it is safe to remove the bean instance from the EJB object and evict it from memory. Clients are unaware of the deactivation process. Remember that the client uses the bean's remote reference, which is implemented by an EJB stub proxy, and therefore does not directly communicate with the bean instance. As a result, the client's connection to the EJB object can be maintained while the bean is passivated.
Activating a bean is the act of restoring a stateful bean instance's state relative to its EJB object. When a method on the passivated EJB object is invoked, the container automatically creates a new instance and sets its fields equal to the data stored during passivation. The EJB object can then delegate the method invocation to the bean as normal.
Since a stateful bean class does not have to be serializable, the exact mechanism for activating and passivating stateful beans is up to the vendor. Note that the transient property is not treated as you might expect when activating a passivated bean. In Java serialization, transient fields are always set to the initial value for that field type when the object is deserialized. Integers are set to 0, Booleans to false, object references to null, and so on. In EJB, transient fields are not necessarily set back to their initial values but can maintain their original values, or any arbitrary value, after being activated. Take care when using transient fields, since their state following activation is implementation-specific.
The activation process is supported by life cycle callback methods. In EJB 3.0 (unlike in EJB 2.1), life cycle callback methods are added to the stateful bean class when they are needed and are not imposed on the bean class by a session bean interface. Bean developers can hook into life cycle callbacks in their stateful bean classes by annotating methods that are interested in these callbacks. A @PostActivate annotated method is called immediately following the successful activation of a bean instance if it is defined in the bean class. It can be used to reset transient fields to an initial value. A @PrePassivate annotated method is called immediately prior to passivation of the bean instance, again, if the bean developer has defined this method. These two methods are especially helpful if the bean instance maintains connections to resources that need to be closed or freed prior to passivation and reobtained following activation. Because the stateful bean instance is evicted from memory, open connections to resources are not maintained.
Primary Services
The primary services include concurrency, transactions, persistence, distributed objects, asynchronous messaging, a timer service, naming, and security.
Because EJB servers handle concurrency, a bean's methods do not have to be made thread-safe. In fact, the EJB specification prohibits the use of the synchronized keyword. Prohibiting the use of the thread synchronization primitives prevents developers from thinking that they control synchronization and enhances the performance of bean instances at runtime. In addition, the EJB specification explicitly prohibits beans from creating their own threads. In other words, as a bean developer, you cannot create a thread within a bean. The EJB container has to maintain complete control over the bean in order to properly manage concurrency, transactions, and persistence. Allowing the bean developer to create arbitrary threads would compromise the container's ability to track what the bean is doing and would make it impossible for the container to manage the primary services.
In the Java Persistence specification, the persistence container protects shared entity data by making a copy of the entity bean instance on a per-transaction basis. Since each transaction has a snapshot of the entity, concurrent multithreaded access is possible. So how does the container protect against stale reads or different transactions trying to update the same entity at the same time? Optimistic concurrency using version fields is one way. Another way is setting the JDBC isolation level to SERIALIZED. Vendor implementations may also provide ways to obtain row locks directly in the database.
Transactions are managed automatically, so, as a bean developer, you don't need to use any APIs to manage a bean's involvement in a transaction. Simply declaring the transactional attributes at deployment time tells the EJB server how to manage the bean at runtime. EJB does provide a mechanism that allows beans to manage transactions explicitly, if necessary.
Persistence in EJB 3.0 has been totally revamped and rearchitected within the Java Persistence specification. While the EJB 2.1 model was component-based persistence, the Java Persistence model is a plain Java-based model (often called POJO Persistence). Entities can be created outside the scope of the EJB container. They are allocated as any other Java object using the new( ) operator. An entity can be attached to container management, or detached. Bean instances are attached to persistent storage through the EntityManager service. The EntityManager service provides methods to create, find, query, remove, and update entity beans. When a bean instance is attached, the container manages the persistent state of the bean and automatically synchronizes the bean with its data source.
An interesting thing about the Java Persistence model is that bean instances can be detached from the EJB container. Bean instances are usually detached from the EJB container when a transaction completes. These detached instances can be sent around the network to remote clients or even saved to disk. Their state can be modified and then reattached to the EJB container by using the EntityManager.merge( ) method. When bean instances are reattached, any changes made to the bean are synchronized with persistent storage. This new persistence model allows EJB developers to throw away the old Data Transfer Object pattern, greatly simplifying application architecture.
Distributed Objects
EJB Timer Service
The EJB Timer Service can be used to schedule notifications that are sent to enterprise beans at specific times.
Enterprise JavaBeans servers can support as many as three kinds of security:
Authentication, Authorization, Secure communication
All naming services do essentially the same thing: they provide clients with a mechanism for locating distributed objects or resources. To accomplish this, a naming service must provide two things: object binding and a lookup API. Object binding is the association of a distributed object with a natural language name or identifier.
Simply put, lookup APIs allow clients to connect to a distributed service and request a remote reference to a specific object.
Enterprise JavaBeans mandates the use of JNDI as a lookup API on Java clients. JNDI supports just about any kind of naming and directory service. Although JNDI can become extraordinarily complex, the way it's used in Java EE applications is usually fairly simple. Java client applications can use JNDI to initiate a connection to an EJB server and to locate a specific EJB. The following code shows how the JNDI API might be used to locate and obtain a reference to the travelAgentRemote EJB:
Object ref = jndiContext.lookup("TravelAgentRemote");
TravelAgentRemote agent = (TravelAgentRemote) PortableRemoteObject.narrow(ref, TravelAgentRemote.class);
Developing Your First Beans
The persistence.xml File
The Java Persistence specification requires a simple XML deployment descriptor file, persistence.xml, which configures basic things like the name of the EntityManager service that will be managing the set of entities deployed in a particular deployment package. It also defines what database the EntityManager service will be communicating with and may also specify additional, vendor-specific properties.
Developing a Session Bean
The Remote Interface
It looks like a plain Java interface, except that it is annotated with the @Remote annotation. Unlike EJB 2.1, also notice that the business methods do not have to throw java.rmi.RemoteException .
The Bean Class
We use the @Stateless annotation to denote this. Although they are not required to, it is good practice for stateless session beans to implement all of their business interfaces so that the client/bean contract can be enforced by the Java compiler
@Stateless class TravelAgentBean implements TravelAgentRemote{
@PersistenceContext (unitName="titan") EntityManager manager;
First, the travelAgentBean class uses the @PersistenceContext annotation to get access to the EntityManager service that it uses to create and find Cabin entities. @Persistence-Context tells the EJB container that it must set the manager field with an EntityManager instance. The EJB container sees that the type of the field is EntityManager and knows that it must set the field to be a reference to an EntityManager service that references the Titan persistence unit we defined in the persistence.xml file. This field will be initialized when the bean instance is instantiated.
Creating a Client Application
Object ref = jndiContext.lookup("TravelAgentBean/remote");
TravelAgentRemote dao = (TravelAgentRemote)ref;
static Context getInitialContext( ) throws javax.naming.NamingException {
Properties p = new Properties( ); // ... Specify the JNDI properties specific to the vendor.
return new javax.naming.InitialContext(p);}
To access an enterprise bean, a client starts by using JNDI to obtain a directory connection to a bean's container. JNDI is an implementation-independent API for directory and naming systems. Every EJB vendor must provide a directory service that is JNDI-compliant. This means that they must provide a JNDI service provider, which is a piece of software analogous to a driver in JDBC. The code used to obtain a JNDI context depends on which EJB vendor you use.
If you are using a standard Java EE component (Servlet, JSP, EJB, or Java EE Application Client), you will not need to set the properties explicitly when creating a JNDI InitialContext , no matter which EJB vendor you are using. That's because the JNDI properties can be configured at deployment time and are applied automatically. A Java EE component would obtain its InitialContext as follows:
static Context getInitialContext( ) throws javax.naming.NamingException { return new javax.naming.InitialContext( );}
This is simpler and more portable than configuring JNDI properties for simple Java clients. All Java EE components use the same JNDI naming system that enterprise beans use to look up any service. Specifically, they require that EJB references be bound to the "java:comp/env/ejb/" namespace.
Object ref = jndiContext.lookup("java:comp/env/ejb/TravelAgentRemote");
At deployment time, you would use the vendor's deployment tools to map that JNDI name to the TravelAgent EJB's remote interface.
The Client application uses the PortableRemoteObject.narrow( ) method to narrow the Object ref to a TRavelAgentRemote reference:
CabinHomeRemote home = (TravelAgentRemote) PortableRemoteObject.narrow(ref,TravelAgentRemote.class);
The PortableRemoteObject.narrow( ) method was first introduced in EJB 1.1 and continues to be used on remote clients in EJB 3.0. It is needed to support the requirements of RMI over IIOP. Because CORBA supports many different languages, casting is not native to CORBA (some languages don't have casting). Therefore, to get a remote reference to travelAgentRemote, we must explicitly narrow the object returned from lookup( ).
Persistence: EntityManager
In older versions of Java EE, the EJB specification was responsible for defining this layer. In Java EE 5, persistence has been spun off into its own specification: Java Persistence 1.0. Persistence provides an ease-of-use abstraction on top of JDBC so that your code can be isolated from database, vendor-specific peculiarities and optimizations. It can also be described as an object-to-relational mapping engine (ORM). This means that the Java Persistence API can automatically map your Java objects to and from a relational database. In addition to object mappings, this service also provides a query language that is very SQL-like but is tailored to work with Java objects rather than a relational schema.
In the new Java Persistence specification, the EntityManager is the central service for all persistence actions. Entities are plain Java objects that are allocated just like any other Java object. They do not become persistent until your code explicitly interacts with the EntityManager to make them persistent.
You can also use Java Persistence outside of an application server and in plain Java SE programs.
Entities Are POJOs
Entities, in the Java Persistence specification, are plain old Java objects (POJOs). You allocate them with the new( ) operator just as you would any other plain Java object. Instances of an entity bean class do not become persistent until they are associated with an EntityManager. For instance. Allocated instances of the Customer class remain POJOs until you ask the EntityManager to create the entity in the database.
Managed Versus Unmanaged Entities
An entity bean instance is either managed (attached) by an entity manager or unmanaged (detached). When an entity is attached to an EntityManager, the manager tracks state changes to the entity and synchronizes those changes to the database whenever the entity manager decides to flush its state. When an entity is detached, it is unmanaged. Any state changes to an entity that is detached are not tracked by the entity manager.
A persistence context is a set of managed entity object instances. Persistence contexts are managed by an entity manager. The entity manager tracks all entity objects within a persistence context for changes and updates made, and flushes these changes to the database using the flush mode rules. Once a persistence context is closed, all managed entity object instances become detached and are no longer managed. Once an object is detached from a persistence context, it can no longer be managed by an entity manager, and any state changes to this object instance will not be synchronized with the database.
When a persistence context is closed, all managed entity objects become detached and are unmanaged.
There are two types of persistence contexts: transaction-scoped and extended persistence contexts.
Transaction-scoped persistence context
Persistence contexts may live as long as a transaction and be closed when a transaction completes. This is called a transaction-scoped persistence context . When the transaction completes, the transaction-scoped persistence context will be destroyed and all managed entity object instances will become detached. Only application server managed persistence contexts can be transaction-scoped. In other words, only EntityManager instances injected with the @PersistenceContext annotation or its XML equivalent may be transaction-scoped.
Extended persistence context
Persistence contexts may also be configured to live longer than a transaction. This is called an extended persistence context . Entity object instances that are attached to an extended context remain managed even after a transaction is complete. This feature is extremely useful in situations where you want to have a conversation with your database but not keep a long-running transaction, as transactions hold valuable resources like JDBC connections and database locks.
Extended persistence contexts may be created and managed by application code. They can also be created and managed by stateful session beans.
Detached entities
Entity instances become unmanaged and detached when a transaction scope or extended persistence context ends. An interesting side effect is that detached entities can be serialized and sent across the network to a remote client. The client can make changes remotely to these serialized object instances and send them back to the server to be merged back and synchronized with the database.
This behavior is very different from the EJB 2.1 entity model, where entities are always managed by the container. In EJB 2.1, applications using entity beans always had a proxy to the entity bean; in EJB 3.0, you work with concrete instances of plain Java classes.
EJB 2.1 code often used the Value Object Pattern (often called Data Transfer Objects). The idea of this pattern was that the entity bean exposed a method that copied its entire state into an object that could be serialized to remote clients (like a Swing application) that needed access to the entity's state.
It is very expensive to make a remote method call to an entity bean from a client. If the client had to call getFirstName( ), getLastName( ), etc., to get information about a customer it was displaying, performance would suffer. This is where the Value Object Pattern came in. EJB 3.0 eliminates the need for this pattern because persistent objects become value objects automatically when they are detached from a persistent context.
Packaging a Persistence Unit
The persistence.xml deployment descriptor defines the identities and configuration properties of each persistence unit described within it.
The set of classes that belong to the persistence unit can be specified, or you can opt for the persistence provider to scan the JAR file automatically for the set of classes to deploy as entities. When scanning is used, the persistence provider will look at every class file within the JAR to determine if it is annotated with the @Entity annotation and, if it is, it will add it to the set of entities that must be mapped.
<persistence> <persistence-unit name="titan">
<properties> <property name="org.hibernate.hbm2ddl">update</property> </properties>
The JAR file of the persistence unit may also optionally contain a mapping XML deployment descriptor called orm.xml in the META-INF directory of the deployment. This file is used to define the mapping between the classes contained in the persistence unit and the database to which they map. Additional mapping files can be referenced using the <mapping-file> element. The value of this element is a classpath location and not a hardcoded URL.
The Persistence Unit Class Set
A persistence unit maps a fixed set of classes to a relational database. By default, if you specify no other metadata within your persistence.xml file, the JAR file that contains persistence.xml will be scanned from its root for any classes annotated with the @Entity annotation. These classes are added to the set of classes the persistence unit will manage. You can specify additional JARs that you want to be scanned using the <jar-file> element. The value of this element is a path relative to the JAR file that contains persistence.xml:
The Cabin class listed within the <class> elements are added to the persistence unit set along with any other classes scanned in the persistence unit's archive.
If you do not want the persistence.xml's JAR file to be scanned, then you can use the <exclude-unlisted-classes> element. <exclude-unlisted-classes/>
The final set of classes is determined by a union of all of the following metadata:
Classes annotated with @Entity in the persistence.xml file's JAR file (unless <exclude-unlisted-classes> is specified)
Classes annotated with @Entity that are contained within any JARs listed with any <jar-file> elements
Classes mapped in the META-INF/orm.xml file if it exists
Classes mapped in any XML files referenced with the <mapping-file> element
Classes listed with any <class> elements
Obtaining an EntityManager
Java SE, entity managers are created using a EntityManagerFactory.
The Persistence class looks for persistence.xml deployment descriptors within your Java classpath. The unitName parameter you pass in will allow the Persistence implementation to locate an EntityManagerFactory that matches the given name.
EntityManagerFactory factory = Persistence.createEntityManagerFactory("CRM");
EntityManager entityManager= factory.createEntityManager( );
factory.close( );
In Java SE, it is recommended that you close( ) the EntityManagerFactory. This frees up any resources that are being held by the factory.
Obtaining a Persistence Context in JavaEE
An EntityManager can be injected directly into an EJB using the @PersistenceContext annotation.
@PersistenceContext(unitName="titan") EntityManager entityManager;
The unitName( ) attribute identifies the persistence. By default, a transaction-scoped persistence context is injected when using this annotation. You can override this default with the type( ) attribute. When you access this transaction-scoped Entity-Manager, a persistence context becomes associated with the transaction until it finishes. This means that if you interact with any entity managers within the context of a transaction, no matter if they are different instances that are injected into different beans, the same persistence context will be used.
You must never call close( ) on an injected entity manager. Cleanup is handled by the application server. If you close an entity manager, an IllegalStateException is thrown.
An EXTENDED entity manager can only be injected into a stateful session bean;
In order to obtain an extended context, a stateful session bean uses the @PersistenceContext annotation with a type of EXTENDED:
@Stateful class MyStatefulBean implements MyStatefulRemote {
@PersistenceContext (unitName="titan", type=PersistenceContextType.EXTENDED) EntityManager manager;
Interacting with an EntityManager
Persisting Entities
When the actual insertion happens depends on a few variables. If persist( ) is called within a transaction, the insert may happen immediately, or it may be queued until the end of the transaction, depending on the flush mode. You can always force the insertion manually within a transaction by calling the flush( ) method.
Finding Entities
find( ) and getReference( )
<T> T find(Class<T> entityClass, Object primaryKey);
<T> T getReference(Class<T> entityClass, Object primaryKey);
Both methods take the entity's class as a parameter, as well as an instance of the entity's primary key. They use Java generics so that you don't have to do any casting.
The find( ) method returns null if the entity is not found in the database. It also initializes the state based on the lazy-loading policies of each property.
getreference( ) differs from find( ) in that if the entity is not found in the database, this method throws a EntityNotFoundException and there is no guarantee that the entity's state will be initialized.
Persistent objects can also be located by using EJB QL. Unlike EJB 2.1, there are no finder methods, and you must create a Query object by calling the EntityManager's createQuery( ), createNamedQuery( ), or createNativeQuery( ) method:
Query query = entityManager.createQuery("from Customer c where id=2");
Customer cust = (Customer)query.getSingleResult( );
Merging Entities
The Java Persistence spec allows you to merge state changes made to a detached entity back into persistence storage using the entity manager's merge( ) method.
Removing Entities entityManager.remove(cabin);
refresh( )
If you are concerned that a current managed entity is not up-to-date with the database, then you can use the EntityManager.refresh( ) method. The refresh( ) method refreshes the state of the entity from the database, overwriting any changes made to that entity:
contains( ) and clear( )
The contains( ) method takes an entity instance as a parameter. If this particular object instance is currently being managed by the persistence context, it returns true.
If you need to detach all managed entity instances from a persistence context, you can invoke the clear( ) method of the EntityManager. Be aware that when you call clear( ) any changes you have made to managed entities are lost. It is wise to call flush( ) before clear( ) is invoked so you don't lose your changes.
flush( ) and FlushModeType
When you call persist( ), merge( ), or remove( ), these changes are not synchronized with the database until the entity manager decides to flush. You can force synchronization anytime by calling flush( ). By default, flushing automatically happens before a correlated query is executed (inefficient implementations may even flush before any query) and at transaction commit time. The exception to this default rule is find( ). A flush does not need to happen when find( ) or getreference( ) is called because finding by a primary key is not something that would be affected by any updates.
Resource Local Transactions
An entity manager's persistence context is usually managed by a JTA transaction in a Java EE environment. When running in a non-Java EE environment, JTA is not available, so the Java Persistence API specification has provided a transaction-like API through the EntityTransaction interface. You can obtain access to an Entity-Transaction through the EntityManager.getTransaction( ) operation.
It is possible for a vendor implementation to allow the use of the EntityTransaction API within a Java EE environment, but the application developer is encouraged to use JTA.
You cannot use EntityTransactions if the transaction type of your persistence unit is JTA.
EntityManagerFactory factory =Persistence.createEntityManagerFactory("titan");
EntityManager manager = factory.createEntityManager( );
EntityTransaction transaction = manager.getTransaction( );
transaction.begin( ); manager.persist(cabin_1); transaction.commit( );
In order to be able to insert a new Cabin entity into the database, we need to interact with the entity manager in a transactional unit. Since we are running outside the application server, we cannot use JTA and must instead use the EntityTransaction API to begin and commit a unit of work.
Mapping Persistent Objects
The Programming Model
The @Entity annotation has one name( ) attribute. This name is used to reference the entity within an EJB QL expression. If you do not provide a value for this attribute, the name defaults to the unqualified name of the bean class.
How you apply the @Id annotation determines whether you will use the Java bean style for declaring your persistent properties or whether you will use Java fields. If you place the @Id annotation on a getter method, then you must apply any other mapping annotations on getter and setter methods in the class. The provider will also assume that any other getter and setter methods in your class represent persistent properties and will automatically map them based on their base name and type.
If we place @Id in field, then the persistence provider will also assume that any other member fields of the class are also persistent properties and will automatically map them based on their base name and type. Any mapping annotations must be placed on member fields, not on getter or setter methods.
XML Mapping File
By default, the persistence provider will look in the META-INF directory for a file named orm.xml, or you can declare the mapping file in the <mapping-file> element in the persistence.xml deployment descriptor.
<entity class="com.titan.domain.Customer" access="PROPERTY"> <attributes> <id name="id"/> </attributes>
Basic Relational Mapping
A developer can take two directions when implementing entity beans. Some applications start from a Java object model and derive a database schema from this model. Other applications have an existing database schema from which they have to derive a Java object model.
The table name defaults to the unqualified class name of the bean. The @Table.uniqueConstraints( ) attribute allows you to specify unique column constraints that should be included in a generated Data Definition Language (DDL).
The table( ) attribute is used for multitable mappings. The unique( ) and nullable( ) attributes define constraints you want placed on the column. You can specify whether you want this column to be included in SQL INSERT or UPDATE by using insertable( ) and updatable( ), respectively. The columnDefinition( ) attribute allows you to define the exact DDL used to define the column type.
The length( ) attribute determines the length of a VARCHAR when you have a String property. For numeric properties, you can define the scale( ) and precision( ) attributes.
Primary Keys
Primary keys can map to one or more properties and must map to one of the following types: any Java primitive type (including wrappers), java.lang.String , or a primary-key class composed of primitives and/or strings.
You can generate the primary key for your entity beans manually or have the persistence provider do it for you. When you want provider-generated keys, you have to use the @GeneratedValue annotation.
Table Generators @TableGenerator
The name( ) attribute defines the name of the @TableGenerator and is the name referenced in the @Id.generator( ) attribute. The table( ), catalog( ), and schema( ) attributes describe the table definition of the generator table. The pkColumnName( ) attribute is the name of the column that identifies the specific entity primary key you are generating for. The valueColumnName( ) attribute specifies the name of the column that will hold the counter for the generated primary key. pkColumnValue( ) is the value used to match up with the primary key you are generating for. The allocationSize( ) attribute is how much the counter will be incremented when the persistence provider queries the table for a new value. This allows the provider to cache blocks so that it doesn't have to go to the database every time it needs a new ID. If you are autogenerating this table, then you can also define some constraints using the uniqueConstraints( ) attribute.
@TableGenerator(name="CUST_GENERATOR" table="GENERATOR_TABLE"
pkColumnName="PRIMARY_KEY_COLUMN" valueColumnName="VALUE_COLUMN" pkColumnValue="CUST_ID" allocationSize=10)
@GeneratedValue (strategy=GenerationType.TABLE, generator="CUST_GENERATOR")
Sequence Generators
The name( ) attribute specifies how this @SequenceGenerator is referenced in @Id annotations. Use the sequenceName( ) attribute to define what sequence table will be used from the database. initialValue( ) is the first value that will be used for a primary key, and allocationSize( ) is how much it will be incremented when it is accessed.
@SequenceGenerator(name="CUSTOMER_SEQUENCE", sequenceName="CUST_SEQ")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CUSTOMER_SEQUENCE")
Primary-Key Classes and Composite Keys
In your bean class, you designate one or more properties that make up your primary key, using the @Id annotation. These properties must map exactly to properties in the @IdClass.
@IdClass(CustomerPK.class) class Customer implements Serializable {
@Id String getLastName( ) { return lastName; }
@Id long getSsn( ) { return ssn; }
CustomerPK pk = new CustomerPK("Burke", 9999999);
Customer cust = entityManager.find(Customer.class, pk);
@EmbeddedId and @Embeddable
There are two ways to map the properties of your primary-key class to columns in your table. One is to specify the @Column mappings within the primary-key class source code; the other is to use @AttributeOverrides.
@Embeddable class CustomerPK implements Serializable {
@Entity class Customer implements Serializable {
@EmbeddedId PK getPk( ) { return pk; }
If you do not want to have the @Column mappings with the primary-key class, or you just want to override them, you can use @AttributeOverrides to declare them directly in your bean class:
@EmbeddedId @AttributeOverrides({@AttributeOverride(name="lastName", column=@Column(name="LAST_NAME"), @AttributeOverride(name="ssn", column=@Column(name="SSN"))})
Property Mappings
the persistence manager would assume that every nontransient property (getter/setter or field, depending on your access type) in your bean class is persistent, even if the property does not have any mapping metadata associated with it.
@Basic and FetchType
This FetchType attribute allows your persistence provider to optimize your access to the database by minimizing the amount of data you load with a query. So, if the fetch( ) attribute is LAZY , that particular property will not be initialized until you actually access this field.
@Basic(fetch=FetchType.LAZY, optional=false)
The optional( ) attribute is useful for when the persistence provider is generating the database schema for you. When this attribute is set to true, the property is treated as nullable.
The @Temporal annotation provides additional information to the persistence provider about the mapping of a java.util.Date or java.util.Calendar property. This annotation allows you to map these object types to a date, a time, or a timestamp field in the database.
The @Lob annotation is used to map these large object types: java.sql.Blob, java.sql.Clob.
@Enumerated The @Enumerated annotation maps Java enum types to the database.
(EnumType.STRING) CustomerType getCustomerType( ) { return customerType; }
Multitable Mappings with @SecondaryTable
Sometimes you have to deal with one logical entity that is stored in two different tables, Java Persistence allows you to map an entity bean class to one or more tables using the @SecondaryTable annotation.
To use the @SecondaryTable annotation, the primary key columns of the ADDRESS_TABLE must be joinable with one or more columns in the CUSTOMER_TABLE:
The name( ) attribute of the @PrimaryKeyJoinColumn annotation represents the column in the ADDRESS_TABLE that you will use in the join. The referencedColumnName( ) attribute represents the column name in the CUSTOMER_TABLE that is used to join with the ADDRESS_TABLE.
SecondaryTables({ @SecondaryTable(name="ADDRESS_TABLE", pkJoinColumns={@PrimaryKeyJoinColumn (name="ADDRESS_ID")}),
@SecondaryTable(name="CREDIT_CARD_TABLE", pkJoinColumns={@PrimaryKeyJoinColumn (name="CC_ID")})})
class Customer implements Serializable {
@Column(name="STREET", table="ADDRESS_TABLE") String getStreet( ) { return street; }
@Embedded Objects
The Java Persistence specification allows you to embed nonentity Java objects within your entity beans and map the properties of this embedded value object to columns within the entity's table. These objects do not have any identity and they are owned exclusively by their containing entity bean class.
@Embeddable class Address implements Serializable {}
As with @EmbeddedId, the @Embedded annotation can be used in conjunction with the @AttributeOverrides annotation if you want to override the column mappings specified in the embedded class.
@Entity @Table(name="CUSTOMER_TABLE")
class Customer implements Serializable {
@Embedded @AttributeOverrides({@AttributeOverride (name="street", column=@Column(name="CUST_STREET")), @AttributeOverride(name="city", column=@Column(name="CUST_CITY")), @AttributeOverride(name="state", column=@Column(name="CUST_STATE")) })
Address getAddress( ) {}
Entity Relationships
The Seven Relationship Types
Seven types of relationships can exist between entity beans. There are four types of cardinality: one-to-one, one-to-many, many-to-one, and many-to-many. In addition, each relationship can be either unidirectional or bidirectional.
One-to-One Unidirectional Relationship
@Entity class Customer implements Serializable {
@OneToOne(cascade={CascadeType.ALL}) @JoinColumn (name="ADDRESS_ID") Address getAddress( ) {}
A one-to-one relationship is specified using the @OneToOne annotation and is mapped with the @JoinColumn annotation.
If you are joining on something other than the primary-key column of the ADDRESS table, then you must use the referencedColumnName( ) attribute. This referencedColumnName( ) must be unique, since this is a one-to-one relationship.
Primary-key join columns
Sometimes the primary keys of the two related entities are used instead of a specific join column. In this case, the primary keys of the related entities are identical, and there is no need for a specific join column.
In this mapping scenario, you are required to use an alternative annotation to describe the mapping@PrimaryKeyJoinColumn.
The referencedColumnName( ) is the column to join to on the related entity. If this is left blank, it is assumed that the related entity's primary key will be used.
The columnDefinition( ) will be used when the persistence provider is generating schema and it will specify the SQL type of the referencedColumnName( ).
@OneToOne(cascade={CascadeType.ALL}) @PrimaryKeyJoinColumn Address getAddress( ) {}
One-to-One Bidirectional Relationship
@Entity class CreditCard implements Serializable {
Customer getCustomer( ) {}
The mappedBy( ) attribute sets up the bidirectional relationship and tells the persistence manager that the information for mapping this relationship to our tables is specified in the Customer bean class, specifically to the creditCard property of Customer. The mappedBy( ) is only used with bidirectional relationships.
With all bidirectional relationship types, including one-to-one, there is always the concept of an owning side of the relationship. Although a setCustomer( ) method is available in the CreditCard bean class, it will not cause a change in the persistent relationship if we set it. When we marked the @OneToOne relationship in the CreditCard bean class with the mappedBy( ) attribute, this designated the CreditCard entity as the inverse side of the relationship. This means that the Customer entity is the owning side of the relationship. If you wanted to associate a CreditCard instance with a different Customer, you would have to call setCreditCard( ) on the old Customer, passing in null, and then call setCreditCard( ) on the new Customer.
Customer newCust = em.find(Customer.class, newCustId);
CreditCard card = oldCustomer.getCreditCard( );
Always wire both sides of a bidirectional relationship when modifying relationships. Entities are like any other Java object that has an association to another object. You have to set the values of both sides of the relationship in memory for the relationship to be updated.
If the customer cancelled his credit card, then you would have to set the Customer's creditCard property to null and remove the CreditCard entity from the database:
Customer cust = em.find(Customer.class, id);
em.remove(cust.getCreditCard( ));
One-to-Many Unidirectional Relationship
@Entity class Customer implements Serializable {
@OneToMany(cascade={CascadeType.ALL}) @JoinColumn(name="CUSTOMER_ID") Collection<Phone> getPhoneNumbers( ) {}
Notice also that we use a Java Generic to templatize the definition of the collection of Phones. Using a Generic is not only good programming practice because it gives a concrete type to your collection, but it also allows the persistence manager to figure out exactly what you are relating the Customer entity to. If you did not use a Generic Collection, then you would have to specify the @OneToMany.targetEntity( ) attribute.
If you need to remove a Phone from the relationship, you need to remove the Phone from both the collection and the database:
cust.getPhones( ).remove(phone);
Removing the Phone from the Customer's collection does not remove the Phone from the database. You have to delete the Phone explicitly; otherwise, it will be orphaned.
Join table mapping
@OneToMany(cascade={CascadeType.ALL}) @JoinTable(name="CUSTOMER_PHONE"), joinColumns={@JoinColumn(name="CUSTOMER_ID")}, inverseJoinColumns={@JoinColumn(name="PHONE_ID")}) Collection<Phone> getPhoneNumbers( ) {}
The joinColumns( ) attribute should define a foreign key mapping to the primary key of the owning side of the relationship. The inverseJoinColumns( ) attribute maps the nonowning side. If either side of the relationship had a composite primary key, we would just add more @JoinColumn annotations to the array.
Many-to-One Unidirectional Relationship
@ManyToOne @JoinColumn (name="SHIP_ID")
One-to-Many Bidirectional Relationship
@Entity class Reservation implements Serializable {
@ManyToOne @JoinColumn(name="CRUISE_ID") }
@Entity class Cruise implements Serializable { @OneToMany(mappedBy="cruise")
As with one-to-one bidirectional relationships, there must be one owning side of a relationship in a one-to-many bidirectional relationship. Java Persistence currently requires that the many-to-one side always be the owner.
Always wire both sides of a bidirectional relationship in your Java code.
Many-to-Many Bidirectional Relationship
To establish a many-to-many bidirectional relationship, we normally create joint table.
@Entity class Reservation implements Serializable {
@ManyToMany @JoinTable (name="RESERVATION_CUSTOMER"),
JoinColumns={@JoinColumn(name="RESERVATION_ID")}, inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")})
Set<Customer> getCustomers( ) { return customers; }
As with all bidirectional relationships, there has to be an owning side.
@Entity class Customer implements Serializable {
@ManyToMany(mappedBy="customers") Collection<Reservation> getReservations( ) {}
Many-to-Many Unidirectional Relationship
Mapping Collection-Based Relationships
The Java Persistence specification also allows you to represent a relationship with a java.util.List or a java.util.Map .
Ordered List-Based Relationship
Normally List actually gives you a bag semantic, an unordered collection that allows duplicates.
A List type can give you the additional ability to order the returned relationship based on a specific set of criteria. This requires the additional metadata that is provided by the @OrderBy annotation.
@ManyToMany @OrderBy("lastName ASC") @JoinTable(name="RESERVATION_CUSTOMER"), joinColumns={@JoinColumn(name="RESERVATION_ID")}, inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")})
List<Customer> getCustomers( ) { return customers; }
If the value( ) attribute is left empty, the List is sorted in ascending order based on the value of the primary key.
You can also specify additional restrictions like @OrderBy('lastname asc, firstname asc").
Map-Based Relationship
The java.util.Map interface can be used to express collection-based relationships. In this case, the persistence provider creates a map with the key being a specific property of the related entity and the value being the entity itself. If you use a java.util.Map, you must use the @MapKey annotation.
The name( ) attribute is the name of the persistent property that you want to represent the key field of the map object. If you leave this blank, it is assumed you are using the primary key of the related entity as the key of the map.
@MapKey(name="number") Map<String, Phone> getPhoneNumbers( ) { return phoneNumbers;}
Detached Entities and FetchType
When an entity instance becomes detached, its state may not be fully initialized because some of its persistent properties or relationships may be marked as lazily loaded in the mapping metadata. Each relationship annotation has a fetch( ) attribute that specifies whether the relationship property is loaded when the entity is queried. If the fetch( ) attribute is set to FetchType.LAZY , then the relationship is not initialized until it is traversed in your code.
It is important to note that this lazy initialization does not happen unless the entity bean is being managed by a persistence context. If the entity bean is detached, the specification is not clear on what actions the persistence provider should perform when accessing an unloaded relationship of a detached entity. Most persistence providers throw some kind of lazy instantiation exception when you call the accessor of the relationship or when you try to invoke an operation on the relationship of a detached entity.
Cascading can be applied to a variety of entity manager operations, including persist( ), merge( ), remove( ), and refresh( ). This feature is enabled by setting the CascadeType of the relationship annotation's cascade( ) attribute. CascadeType includes ALL, PERSIST, MERGE, REMOVE, REFRESH.
Entity Inheritance
The Java Persistence specification provides three different ways to map an inheritance hierarchy to a relational database:
A single table per class hierarchy
One table will have all properties of every class in the hierarchy.
A table per concrete class
Each class will have a table dedicated to it, with all of its properties and the properties of its superclass mapped to this table.
A table per subclass
Each class will have its own table. Each table will have only the properties that are defined in that particular class. These tables will not have properties of any superclass or subclass.
A single table per class hierarchy
One table will have all properties of every class in the hierarchy.
The single table per class hierarchy mapping also requires an additional discriminator column. This column identifies the type of entity being stored in a particular row.
@Entity @Table(name="PERSON_HIERARCHY") @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DISCRIMINATOR", discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("PERSON") class Person {}
The @Inheritance annotation is used to define the persistence strategy for the inheritance relationship.
The @Inheritance annotation only has to be placed on the root of the class hierarchy, unless you are changing the mapping strategy of a subclass.
Since one table is representing the entire class hierarchy, the persistence provider needs some way to identify which class the row in the database maps to. It determines this by reading the value from the discriminator column. The @DiscriminatorColumn annotation identifies which column in our table will store the discriminator's value.
The @DiscriminatorValue annotation defines what value the discriminator column will take for rows that store an instance of a Person class. You can leave this attribute undefined if you want to. In that case, the persistence manager would generate a value for you automatically. This value would be vendor-specific if the DiscriminatorType is CHAR or INTEGER . The entity name is used by default when a type of STRING is specified. It is good practice to specify the value for CHAR and INTEGER values.
@Entity @DiscriminatorValue ("CUST") class Customer extends Person {}
// use the default discriminator value
@Entity class Employee extends Customer {}
The SINGLE_TABLE mapping strategy is the simplest to implement and performs better than all the inheritance strategies. There is only one table to administer and deal with. The persistence engine does not have to do any complex joins, unions, or subselects when loading the entity or when traversing a polymorphic relationship, because all data is stored in one table.
One huge disadvantage of this approach is that all columns of subclass properties must be nullable. So, if you need or want to have any NOT NULL constraints defined on these columns, you cannot do so. Also, because subclass property columns may be unused, the SINGLE_TABLE strategy is not normalized.
Table per Concrete Class
In the table per concrete class strategy, a database table is defined for each concrete class in the hierarchy. Each table has columns representing its properties, and all properties of any superclasses.
The advantage to this approach over the SINGLE_TABLE strategy is that you can define constraints on subclass properties. Another plus is that it might be easier to map a legacy, preexisting schema using this strategy.
This strategy is not normalized, as it has redundant columns in each of its tables for each of the base class's properties. Also, to support this type of mapping, the persistence manager has to do some funky things. One way it could be implemented is for the container to use multiple queries when loading an entity or polymorphic relationship. This is a huge performance hit because the container has to do multiple round trips to the database. Another way a container could implement this strategy is to use SQL UNION s. This still would not be as fast as the SINGLE_TABLE strategy, but it would perform much better than a multiselect implementation. The downside to an SQL UNION is that not all relational databases support this SQL feature. It is probably not wise to pick this strategy when developing your entity beans, unless you absolutely have to.
Table per Subclass
In the table per subclass mapping, each subclass has its own table, but this table contains only the properties that are defined on that particular class. In other words, it is similar to the TABLE_PER_CLASS strategy, except the schema is normalized. This is also called the JOINED strategy.
When the persistence manager loads an entity that is a subclass or traverses a polymorphic relationship, it does an SQL join on all the tables in the hierarchy. In this mapping, there must be a column in each table that can be used to join each table.
@Entity @Inheritance(strategy=InheritanceType.JOINED) class Person {}
@Entity @PrimaryKeyJoinColumn (name="EMP_PK") class Employee extends Customer {}
The persistence manager needs to know which columns in each table will be used to perform a join when loading an entity with a JOINED inheritance strategy. The @PrimaryKeyJoinColumn annotation can be used to describe this metadata.
The name( ) attribute refers to the column you will perform a join on that is contained in the current table. It defaults to the primary-key column of the superclass's table. The referencedColumnName( ) is the column that will be used to perform the join from the superclass's table. It can be any column in the superclass's table, but it defaults to its primary key. If the primary-key column names are identical between the base and subclasses, then this annotation is not needed.
Although it is not as fast as the SINGLE_TABLE strategy, you are able to define NOT NULL constraints on any column of any table and your model is normalized.
This mapping is better than the TABLE_PER_CLASS strategy for two reasons. One, the relational database model is completely normalized. Two, it performs better than the TABLE_PER_CLASS strategy if SQL UNION s are not supported.
It does not perform as well as the SINGLE_TABLE strategy.
Nonentity Base Classes
Sometimes, however, you need to inherit from a nonentity superclass. This superclass may be an existing class in your domain model that you do not want to make an entity. The @MappedSuperclass annotation allows you to define this kind of mapping.
@MappedSuperclass class Person { @Id @GeneratedValue}
@Entity @Table(name="CUSTOMER") @Inheritance(strategy=InheritanceType.JOINED) @AttributeOverride(name="lastname", column=@Column(name="SURNAME"))
class Customer extends Person {}
Since it is not an entity, the mapped superclass does not have an associated table. Any subclass inherits the persistence properties of the base class. You can override any mapped property of the mapped class by using the @AttributeOverride annotation.
You can have @MappedSuperclass annotated classes in between two @Entity annotated classes in a given hierarchy. Also, nonannotated classes (i.e., not annotated with @Entity nor @MappedSuperclass), are completely ignored by the persistence provider.
Queries and EJB QL
Queries in Java Persistence are done using both the EJB QL query language and native SQL.
To execute queries, you reference the properties and relationships of your entity beans rather than the underlying tables and columns these objects are mapped to. When an EJQ QL query is executed, the entity manager uses the information you provided through the mapping metadata, and automatically translates it to one (or several) native SQL query. This generated native SQL is then executed through a JDBC driver directly on your database. Since EJB QL is a query language that represents Java objects, it is portable across vendor database implementations because the entity manager handles the conversion to raw SQL for you.
EJB QL existed in the EJB 2.1 specification, and it is really the only feature that survived in the new release. Although it was well-formed, EJB QL in EJB 2.1 was incomplete, forcing developers to escape to JDBC or write really inefficient code. EJB QL has been greatly improved and expanded to be more parallel to SQL and should now meet most of your needs. Things like projection, GROUP BY, and HAVING have been added, as well as bulk updates and deletes.
EJB QL and native SQL queries are executed through the Query interface.
Query API
try { Query query = entityManager.creatQuery("from Customer c where c.firstName='Bill' and c.lastName='Burke'");
Customer cust = (Customer)query.getSingleResult( );
} catch (EntityNotFoundException notFound) {
} catch (NonUniqueResultException nonUnique) {}
Since both of these exceptions are RuntimeException s, the example code is not required to have a full try/catch block.
java.util.List bills = query.getResultList( );
Much like a java.sql.PreparedStatement in JDBC, EJB QL allows you to specify parameters in query declarations so that you can reuse and execute the query multiple times on different sets of parameters. Two syntaxes are provided: named parameters and positional parameters.
Query query = entityManager.createQuery("from Customer c where c.firstName=:first and c.lastName=:last");
query.setParameter("first", first); query.setParameter("last", last);
The : character followed by the parameter name is used in EJB QL statements to identify a named parameter.
Query query = entityManager.createQuery("from Customer c where c.firstName=?1 and c.lastName=?2");
query.setParameter(1, first); query.setParameter(2, last);
Using named parameters over positional parameters is recommended as the EJB QL code becomes self-documenting. This is especially useful when working with predeclared queries.
Date Parameters
If you need to pass java.util.Date or java.util.Calendar parameters into a query, you need to use special setParameter methods:
Query setParameter(String name, java.util.Date value, TemporalType temporalType);
A Date or Calendar object can represent a real date, a time of day, or a numeric timestamp. Because these object types can represent different things at the same time, you need to tell your Query object how it should use these parameters. The TemporalType passed in as a parameter to the setParameter( ) method tells the Query interface what database type to use when converting the java.util.Date or java.util.Calendar parameter to a native SQL type.
Paging Results
query.setMaxResults(max).setFirstResult(index).getResultList( );
We limit the number of customers it returns by using the setMaxResults( ) method, passing in the max method parameter. The method is also designed so that you can define an arbitrary set of results that you want returned by the execution of the query. The setFirstResult( ) method tells the query what position in the executed query's result set you want returned.
List results
int first = 0; int max = 10;
do { results = getCustomers(max, first); Iterator it = results.iterator( );
while (it.hasNext( )) { Customer c = (Customer)it.next( );
System.out.println(c.getFirstName() + " " + c.getLastName( ));}
entityManager.clear( ); first = first + results.getSize( );}
In this example, we loop through all customers in the database and output their first and last names to the system output stream. If we had thousands or even millions of customers in the database, we could quickly run out of memory, as each execution of the getCustomers( ) method would return customers that were still managed by the entity manager. So, after we are finished outputting a block of customers, we call EntityManager.clear( ) to detach these customers and let them be garbage-collected by the Java VM. Use this pattern when you need to deal with a lot of entity objects within the same transaction.
Some Java Persistence vendors will provide additional add-on features that you can take advantage of when executing a query. For instance, the JBoss EJB 3.0 implementation allows you to define a timeout for the query. These types of add-on features can be specified as hints using the setHint( ) method on the query.
Query query = manager.createQuery("from Customer c");
query.setHint("org.hibernate.timeout", 1000);
The setHint( ) method takes a string name and an arbitrary object parameter.
EJB QL is expressed in terms of the abstract persistence schema of an entity: its abstract schema name, basic properties, and relationship properties. EJB QL uses the abstract schema names to identify beans, the basic properties to specify values, and the relationship properties to navigate across relationships.
Abstract Schema Names
The abstract schema name can be defined by metadata or it can default to a specific value. It defaults to the unqualified name of the entity bean class if the name( ) attribute is not specified when declaring the @Entity annotation.
Simple Queries
SELECT OBJECT( c ) FROM Customer AS c
The OBJECT( ) operator is optional and is a relic requirement of the EJB 2.1 spec. It is there for backward compatibility.
Selecting Entity and Relationship Properties
EJB QL allows SELECT clauses to return any number of basic or relationship properties.
SELECT c.firstName, c.lastName FROM Customer AS c
If you use get or set methods to specify your persistent properties, then the property name is extracted from the method name. If you are mapping your entity directly on the member fields of your bean class, then the field name is used in the SELECT clause.
When a query returns more than one item, you must use the Query.getResultList( ) method. If the SELECT clause queries more than one column or entity, the results are aggregated in an object array (Object[]) in the java.util.List returned by geTResultList( ).
Query query = manager.createQuery( "SELECT c.firstName, c.lastName FROM Customer AS c");
List results = query.getResultList( ); Iterator it = results.iterator( );
while (it.hasNext( )) { Object[] result = (Object[])it.next( );
String first = (String)result[0]; String last = (String)result[1]; }
SELECT c.creditCard.creditCompany.address.city FROM Customer AS c
You can also use single-valued relationship field types in select statements.
Paths can be as long as required. It's common to use paths that navigate over one or more relationship fields to end at either a basic or a relationship property.
Paths cannot navigate beyond persistent properties.
It's illegal to navigate across a collection-based relationship field. The following EJB QL statement is illegal
SELECT c.reservations.cruise FROM Customer AS c
Constructor Expressions
One of the most powerful features of EJB QL is the ability to specify a constructor within the SELECT clause that can allocate plain Java objects (nonentities) and pass in columns you select into that constructor.
SELECT new com.titan.domain.Name(c.firstName, c.lastName) FROM Customer c
The IN Operator and INNER JOIN
The IN operator allows an identifier to represent individual elements in a collection-based relationship field. The IN operator assigns the individual elements in the reservations property to the r identifier. Once we have an identifier to represent the individual elements of the collection, we can reference them directly and even select them in the EJB QL statement. We can also use the element identifier in path expressions.
SELECT r.cruise FROM Customer AS c, IN( c.reservations ) r
This query can also be expressed as an INNER JOIN(The INNER keyword is actually optional).
SELECT r.cruise FROM Customer c INNER JOIN c.reservations r
The LEFT JOIN syntax enables retrieval of a set of entities where matching values in the join statement may not exist. For values that do not exist, a null value is placed in the result set.
SELECT c.firstName, c.lastName, p.number From Customer c LEFT JOIN c.phoneNumbers p
Fetch Joins
The JOIN FETCH syntax allows you to preload a returned entity's relationships even if the relationship property has a FetchType of LAZY .
Famous N + 1 problem, as we have to do N extra queries beyond our initial query.
When tuning database applications, it is always important to reduce the number of round trips made to the database as much as possible. This is where the JOIN FETCH syntax comes into play.
SELECT c FROM Customer c LEFT JOIN FETCH c.phones
Using LEFT JOIN FETCH will additionally preload the Phone association. This can have a dramatic effect on performance because instead of N + 1 queries, only one query is made to the database.
Using DISTINCT
The DISTINCT keyword ensures that the query does not return duplicates.
SELECT DISTINCT cust FROM Reservation AS res, IN (res.customers) cust
The WHERE Clause
The WHERE clause is composed of conditional expressions that reduce the scope of the query and limit the number of items selected. Several conditional and logical operators can be used in expressions; they are listed here in order of precedence:
Navigation operator (.) Arithmetic operators
Comparison operators: =, >, >=, <, <=, <> (not equal), LIKE, BETWEEN, IN, IS NULL, IS EMPTY, MEMBER OF
Logical operators: NOT, AND, OR
The arithmetic operators allow a query to perform arithmetic in the process of doing a comparison. Arithmetic operators can be used only in the WHERE clause, not in the SELECT clause.
The WHERE Clause and Equality Semantics
You can also compare entity objects for equality, but these too must be of the same type. To be more specific, they must both be entity object references to beans from the same deployment. As an example, the following query finds all the Reservation entities made by a specific Customer. It takes a Customer entity as a parameter:
SELECT r FROM Reservation r, IN ( r.customers ) AS cust WHERE cust = :specificCustomer
SELECT s FROM Ship AS s WHERE s.tonnage NOT BETWEEN 80000.00 AND 130000.00
The WHERE Clause and IN
The IN conditional operator used in the WHERE clause is not the same as the IN operator used in the FROM clause (that's why the JOIN keyword in the FROM clause should be preferred over the IN keyword for collection navigation). In the WHERE clause, IN tests for membership in a list of literal values.
SELECT c FROM Customer AS c WHERE c.address.state NOT IN ('FL', 'TX', 'MI', 'WI', 'MN')
The IN operator can also be used with input parameters.
SELECT c FROM Customer AS c WHERE c.address.state IN ( ?1, ?2, ?3, 'WI', 'MN')
SELECT c FROM Customer AS c WHERE c.address IS NOT NULL
The NULL comparison operator can also be used to test input parameters. In this case, NULL is usually combined with the NOT operator to ensure that an input parameter is not a null value. For example, this query can be used to test for null input parameters. The EJB QL statement first checks that the city and state input parameters are not null and then uses them in comparison operations:
SELECT c FROM Customer AS c WHERE :city IS NOT NULL AND :state IS NOT NULL AND c.address.state = :state AND c.address.city = :city
In this case, if either of the input parameters is a null value, the query returns an empty List , avoiding the possibility of UNKNOWN results from null input parameters. Your Java code should do these null checks up front to avoid an unnecessary database roundtrip.
The WHERE Clause and IS EMPTY
The IS EMPTY operator allows the query to test whether a collection-based relationship is empty.
Remember that a collection-based relationship will never be null. If a collection-based relationship field has no elements, it returns an empty Collection or Set.
SELECT crs FROM Cruise AS crs WHERE crs.reservations IS NOT EMPTY
It is illegal to use IS EMPTY against collection-based relationships that have been assigned an identifier in the FROM clause.
The WHERE Clause and MEMBER OF
The MEMBER OF operator is a powerful tool for determining whether an entity is a member of a specific collection-based relationship.
SELECT crs FROM Cruise AS crs, IN (crs.reservations) AS res, Customer AS cust WHERE cust = :myCustomer AND cust MEMBER OF res.customers
The WHERE Clause and LIKE
The LIKE comparison operator allows the query to select String type fields that match a specified pattern.
You can use two special characters when establishing a comparison pattern: % (percent) stands for any sequence of characters and _ (underscore) stands for any single character. You can use these characters at any location within a string pattern. If a % or _ actually occurs in the string, you can escape it with the \ character.
phone.number LIKE '617%'
Functional Expressions
Functional expressions in the WHERE clause
LOWER(String), UPPER(String), CONCAT(String1, String2), LOCATE(String1, String2 [, start]), SUBSTRING(String1, start, length)
TRIM([[LEADING | TRAILING | BOTH] [trim_char] FROM] String)
Allows you to trim a specified character from the beginning (LEADING), end (trAILING), or both (BOTH). If you do not specify a trim character, the space character will be assumed.
The arithmetic functions: ABS(number), SQRT(double), MOD(int, int)
Functions returning dates and times
EJB QL has three functions that can return you the current date, time, and timestamp: CURRENT_DATE, CURRENT_TIME, and CURRENT_TIMESTAMP.
Aggregate functions in the SELECT clause
COUNT (identifier), MAX( path expression), MIN( path expression), AVG( numeric ), SUM( numeric)
DISTINCT, nulls, and empty arguments
The DISTINCT operator can be used with any of the aggregate functions to eliminate duplicate values.
SELECT DISTINCT COUNT(c.address.zip) FROM Customers AS c WHERE c.address.zip LIKE '554%'
The DISTINCT operator first eliminates duplicate Zip codes; After the duplicates have been eliminated, the COUNT( ) function counts the number of items left.
Any field with a null value is automatically eliminated from the result set operated on by the aggregate functions. The COUNT( ) function also ignores values with null values.
The ORDER BY Clause SELECT c FROM Customers AS c ORDER BY c.lastName ASC, c.firstName DESC
GROUP BY and HAVING
The GROUP BY and HAVING clauses are commonly used to apply stricter organization to a query and to narrow the results for aggregate functions. The GROUP BY clause is usually used in combination with aggregate functions, because it allows you to cluster data by category. The GROUP BY clause must specify one of the columns that you are returning in the query.
SELECT new ReservationSummary(cr.name, COUNT(res), SUM(res.amountPaid)) FROM Cruise cr LEFT JOIN cr.reservations res GROUP BY cr.name
The HAVING clause is used with a GROUP BY clause and acts as a filter, restricting the final output. The HAVING clause employs aggregate functional expressions using only the identifiers used in the SELECT clause. You can restrict the GROUP BY result by using the HAVING syntax.
SELECT cr.name, COUNT (res) FROM Cruise cr JOIN cr.reservations res GROUP BY cr.name HAVING count(res) > 10
Subqueries are SELECT statements embedded in another query. EJB QL supports subqueries in WHERE and HAVING clauses. Subqueries are very useful when normal mechanisms for narrowing your search cannot obtain the data you desire.
SELECT COUNT(res) FROM Reservation res WHERE res.amountPaid > (SELECT avg(r.amountPaid) FROM Reservation r)
You can also reference identifiers in the FROM clause of the outer query of your subquery.
FROM Cruise cr WHERE 100000 < ( SELECT SUM(res.amountPaid) FROM cr.reservations res)
When a subquery returns multiple rows, it is possible to quantify the results with the ALL, ANY, and SOME expressions.
The ALL operator returns TRue if all the things in the subquery match the conditional expression.The ANY operator returns true if anything in the subquery matches the conditional expression.
SOME is a synonym of ANY, and the two are syntactically equivalent.
FROM Cruise cr WHERE 0 < ALL (SELECT res.amountPaid from cr.reservations res)
The EXISTS operator returns true if the subquery result consists of one or more values. If no values are returned by the subquery, then false is returned.
FROM Cruise cr WHERE EXISTS (SELECT res FROM cr.reservations WHERE res.amountPaid = 0)
Bulk UPDATE and DELETE
Java Persistence has the ability to perform bulk UPDATE and DELETE operations. This can save you a lot of typing.
UPDATE Reservation res SET res.amountPaid = (res.amountPaid + 10) WHERE EXISTS ( SELECT c FROM res.customers c WHERE c.firstName = 'Bill' AND c.lastName='Burke' )
DELETE FROM Reservation res WHERE EXISTS ( SELECT c FROM res.customers c WHERE c.firstName = 'Bill' AND c.lastName='Burke')
Native Queries
The entity manager service provides a way to create native SQL queries and map them to your objects. Native queries can return entities, column values, or a combination of the two.
Query createNativeQuery(String sql)
Simple Entity Native Queries
Query createNativeQuery(String sql, Class entityClass)
A simple entity native query takes an SQL statement and implicitly maps it to one entity based on the mapping metadata you declared for that entity. It expects that the columns returned in the result set of the native query will match perfectly with the entity's O/R mapping. The entity the native SQL query maps to is determined by the entityClass parameter.
Query query = manager.createNativeQuery("SELECT p.phone_PK, p.phone_number, p.type FROM PHONE AS p", Phone.class);
Complex Native Queries
Query createNativeQuery(String sql, String mappingName)
This entity manager method allows you to have complex mappings for your native SQL. You can return multiple entities and scalar column values at the same time. The mappingName parameter references a declared @SqlResultSetMapping . This annotation is used to define how the native SQL results hook back into your O/R model. If your returned column names don't match the parallel annotated property mapping, you can provide a field-to-column mapping for them using @FieldResult.
@Entity @SqlResultSetMapping(name="customerAndCreditCardMapping", entities={@EntityResult(entityClass=Customer.class),
@EntityResult(entityClass=CreditCard.class, fields={@FieldResult(name="id", column="CC_ID"),
@FieldResult(name="number", column="number")} )})
class Customer {…}
{ Query query = manager.createNativeQuery( "SELECT c.id, c.firstName, cc.id As CC_ID, cc.number" + "FROM CUST_TABLE c, CREDIT_CARD_TABLE cc" + "WHERE c.credit_card_id = cc.id", "customerAndCreditCardMapping");}
Because the result set returns multiple entity types, we must define an @SqlResultSetMapping . This annotation can be placed on an entity class or method. The entities( ) attribute is set to an array of @EntityResult annotations. Each @EntityResult annotation specifies the entities that will be returned by the native SQL query.
Mixed scalar and entity results
For our final example, let's show an entity and scalar value mix. We'll write a native SQL query that returns a list of cruises and how many reservations each cruise has.
entities=@EntityResult(name="com.titan.domain.Cruise", fields=@FieldResult(name="id", column="id")),
@Entity class Cruise {...}
{ Query query = manager.createNativeQuery( "SELECT c.id, count(Reservation.id) as resCount FROM Cruise c LEFT JOIN Reservation ON c.id = Reservation.CRUISE_ID GROUP BY c.id", "reservationCount"); }
The reservationCount mapping declares that the native SQL query represents a request for a Cruise entity and a count of all the reservations for that cruise. The @FieldResult annotation identifies the c.id column as being associated with a Cruise entity. The @ColumnResult annotation identifies the resCount column as a scalar value.
Named Queries
Java Persistence provides a mechanism so that you can predefine EJB QL or native SQL queries and reference them by name when creating a query. You would want to predeclare queries for the same reason you create String constant variables in Java: to reuse them in multiple different situations. If you predefine your queries in one place, you have an easy way to fine-tune or modify them as time goes on. The @NamedQuery annotation is used for predefining EJB QL.
@NamedQueries({ @NamedQuery (name="getAverageReservation", query= "SELECT AVG( r.amountPaid) FROM Cruise As c, JOIN c.reservations r WHERE c = :cruise"),
@NamedQuery(name="findFullyPaidCruises", query= "FROM Cruise cr WHERE 0 < ALL ( SELECT res.amountPaid from cr.reservations res )") })
@Entity class Cruise {...}
You can then reference these declarations in the EntityManager.createNamedQuery( ) method:
Query query = em.createNamedQuery("findFullyPaidCruises");
Query.setParameter("cruise", cruise);
Named Native Queries
The @NamedNativeQuery annotation is used for predefining native SQL queries.
@NamedNativeQuery( name="findCustAndCCNum", query="SELECT c.id, c.firstName, c.lastName, cc.number AS CC_NUM FROM CUST_TABLE c, CREDIT_CARD_TABLE cc WHERE c.credit_card_id = cc.id",
entities={@EntityResult(entityClass=Customer.class)}, columns={@ColumnResult(name="CC_NUM")})
@Entity class Customer {...}
You can then reference this declaration in the EntityManager.createNamedQuery( ) method:
Query query = em.createNamedQuery("findCustAndCCNum");
The resultClass( ) attribute is for when you have a native query that returns only one entity type. The resultSetMapping( ) attribute must resolve to a predeclared @SqlResultSetMapping . Both attributes are optional, but you must declare at least one of them.
Entity Callbacks and Listeners
The Java Persistence specification allows you to set up callback methods on your entity classes so that your entity instances are notified when these events occur. You can also register separate listener classes that can intercept these same events. These are called entity listeners .
Callback Events
A certain annotation represents each phase of an entity's life cycle:
@PrePersist,@PostPersist, @PostLoad, @PreUpdate, @PostUpdate, @PreRemove, @PostRemove.
Callbacks on Entity Classes
You can have an entity bean instance register for a callback on any of these life cycle events.
@Entity class Cabin { @PostPersist void afterInsert( ) {}
Entity Listeners
Entity listeners are classes that can generically intercept entity callback events. They are not entity classes themselves, but they can be attached to an entity class through a binding annotation or XML. You can assign methods on an entity listener class to intercept a particular life cycle event. These methods return void and take one Object parameter that is the entity instance on which the event is being triggered. The method is annotated with the callback in which it is interested.
class TitanAuditLogger {
@PostPersist void postInsert(Object entity) { System.out.println("Inserted entity: " + entity.getClass().getName( )); }}
The entity listener can be applied to an entity class by using the @EntityListeners annotation
You can specify one or more entity listeners that intercept the callback events of an entity class:
@Entity @EntityListeners ({TitanAuditLogger.class, EntityJmxNotifier.class}) class Cabin {}
The execution order of entity listeners is the order they were declared in the @EntityListeners annotation or ORM XML mapping file. Any callbacks on the entity bean class itself are called last.
Default Entity Listeners
You can specify a set of default entity listeners that are applied to every entity class in the persistence unit by using the <entity-listeners> element under the top-level <entity-mappings> element in the ORM mapping file.
<entity-listener class="com.titan.listeners.TitanAuditLogger">
<post-persist name="afterInsert"/> <post-load name="afterLoading"/>
</entity-listener> <entity-listener class="com.titan.listeners.EntityJmxNotifier"/>
If you want to turn off default entity listeners to a particular entity class, you can use the @ExcludeDefaultListeners annotation:
@Entity @ExcludeDefaultListeners class Cabin {}
Inheritance and Listeners
If you have an inheritance entity hierarchy in which the base class has entity listeners applied to it, any subclass will inherit these entity listeners. If the subclass also has entity listeners applied to it, then both the base and the subclass's listeners will be attached.
Entity listeners applied to a base class happen before any listeners attached to a subclass. Callback methods defined directly in an entity class happen last.
You can turn off inherited entity listeners by using @ExcludeSuperclassListeners.
Session Beans
Session beans are divided into two basic types: stateless and stateful. A stateless session bean is a collection of related services, each represented by a method; the bean maintains no state from one method invocation to the next. When you invoke a method on a stateless session bean, it executes the method and returns the result without knowing or caring what other requests have gone before or might follow.
A stateful session bean is an extension of the client application. It performs tasks on behalf of a client and maintains state related to that client. This state is called conversational state because it represents a continuing conversation between the stateful session bean and the client. Methods invoked on a stateful session bean can write and read data to and from this conversational state, which is shared among all methods in the bean.
Depending on the vendor, stateful session beans may have a timeout period. If the client fails to use the stateful bean before it times out, the bean instance is destroyed and the EJB object reference is invalidated. This prevents the stateful session bean from lingering long after a client has shut down or otherwise has finished using it. After Stateless session beans have longer lives because they do not retain any conversational state and are not dedicated to one client. As soon as a stateless session bean has finished a method invocation, it can be reassigned to service a new client. Stateless session beans may also have a timeout period and can be removed by the client, but the impact of a bean timeout or removal is different than with a stateful session bean. A timeout or remove operation simply invalidates the EJB object reference for that client; the bean instance is not destroyed and is free to service other client requests.
Whether they are stateful or stateless, session beans are not persistent, like entity beans are. In other words, session beans don't represent persistent data and are not saved to the database.
The Stateless Session Bean
A Stateless session bean can be swapped freely between EJB objects because it isn't dedicated to one client and doesn't maintain any conversational state. As soon as it is finished servicing a method invocation it can be swapped to another EJB object. Because it does not maintain conversational state, a stateless session bean does not require passivation or activation, further reducing the overhead of swapping. In short, stateless session beans are lightweight and fast.
The ProcessPayment EJB
The business interface
interface ProcessPayment {}
The EJB specification allows you to define a common base class for your remote and local interfaces if they share the same methods.
@Remote interface ProcessPaymentRemote extends ProcessPayment {}
@Local interface ProcessPaymentLocal extends ProcessPayment{}
Checked exceptions (non-RuntimeException s), by default, do not cause a transaction rollback. Instead of throwing these types of exceptions directly, you should catch them in a try/catch block and throw a more appropriate exception. A common practice is to wrap these checked exceptions in a EJBException , as these types of subsystem errors are unrecoverable.
An EJBException indicates that the container ran into problems processing a business interface invocation. EJBException is unchecked (it extends java.lang.RuntimeException ), so you won't get a compile error if you don't catch it. However, under certain circumstances, it is a good idea to catch EJBException, and in other circumstances, it should be propagated.
All exceptions thrown by Java Persistence interfaces are RuntimeExceptions. Your client code must be aware of this if it needs to take action on specific persistence exceptions. Exception behavior can be declared explicitly using the @ApplicationException and the <application-exception> XML deployment descriptor metad
The bean class: ProcessPaymentBean
@Stateless class ProcessPaymentBean implements ProcessPaymentRemote, ProcessPaymentLocal {}
@Stateless @Local(ProcessPaymentLocal.class) @Remote(ProcessPaymentRemote.class)
class ProcessPaymentBean {}
When used on the bean class, the @Local and @Remote annotations take an array of interface classes. It is not recommended that you use this approach unless you have to, as implementing your business interfaces directly enforces the contract between the bean class and these interfaces.
Accessing environment properties (injection)
@Resource(mappedName="titanDB") DataSource dataSource;
@Resource(name="min") int minCheckNumber;
Each EJB container has its own internal registry where it stores configuration values and references to external resources and services. This registry is called the Enterprise Naming Context (ENC). @javax.annotation.Resource . This tells the EJB container that when an instance of the bean class is instantiated, those fields must be initialized with values in the container's ENC.
the @Resource annotation that tags the datasource field contains a mappedName( ) attribute which identifies the external JDBC data source that should be mapped into the ENC. For minCheckNumber, the @Resource annotation identifies a named value within the ENC that may be used to initialize the field externally.
The SessionContext object can be used as the bean instance's interface to the EJB container to obtain information about the context of the method invocation call and to provide quick access to various EJB services. A session bean can obtain a reference to its SessionContext by using the @Resource annotation: @Resource SessionContext ctx;
The SessionContext.getBusinessObject( ) method returns a reference to the current EJB that can be invoked on by other clients. This reference is the EJB equivalent to Java's this pointer. The businessInterface parameter must be one of the EJB's remote or local interfaces so that the container knows whether to create a remote or local reference to the current EJB. The getBusinessObject( ) method allows the bean instance to get its own EJB object reference, which it can then pass to other beans.
It is illegal for a bean instance to pass a this reference to another bean; instead, it passes its remote or local EJB object reference, which the bean instance gets from its SessionContext.
The SessionContext.getInvokedBusinessInterface( ) method allows you to determine whether your EJB was invoked on through its remote, local, or web service interface. It returns the invoked business interface as a class.
EJBContext.lookup( ) is a convenience method that allows you to look up entries in the EJB's ENC.
The EJBContext.getTimerService( ) method returns a reference to the container's Timer Service, which allows the stateless bean to set up notifications of timed events for itself. In other words, a session bean can set alarms so that the container will call it when a specific date arrives or some interval of time has passed.
The EJBContext.getCallerPrincipal( ) method is used to obtain the java.security.Principal object representing the client that is currently accessing the bean. The Principal object can be used by an EJB to track the identities of clients making updates.
The EJBContext.isCallerInRole( ) method tells you whether the client accessing the bean is a member of a specific role, identified by a role name.
and The transactional methodsgetUserTransaction( ), setRollbackOnly( ), and geTRollbackOnly( ).
The Life Cycle of a Stateless Session Bean
Stateless beans define instance pooling in their life cycles. When the number of stateless instances servicing client requests is insufficient, more can be created and added to the pool.
Transitioning to the Method-Ready Pool
When an instance transitions from the Does Not Exist state to the Method-Ready Pool, three operations are performed on it. First, the bean instance is instantiated by invoking the Class.newInstance( ) method on the stateless bean class. Second, the container injects any resources that the bean's metadata has requested via an injection annotation or XML deployment descriptor.
Finally, the EJB container will post a post-construction event. The bean class can register for this event by annotating a method with @javax.annotation.PostConstruct.
Stateless session beans are not subject to activation, so they can maintain open connections to resources for their entire life cycles.[*] The @PreDestroy method should close any open resources before the stateless session bean is evicted from memory at the end of its life cycle.
Once an instance is in the Method-Ready Pool, it is ready to service client requests. When a client invokes a business method on an EJB object, the method call is delegated to any available instance in the Method-Ready Pool. While the instance is executing the request, it is unavailable for use by other EJB objects. Once the instance has finished, it is immediately available to any EJB object that needs it. Stateless session instances are dedicated to an EJB object only for the duration of a single method call.
When an instance is swapped in, its SessionContext changes to reflect the context of the EJB object and the client invoking the method. The bean instance may be included in the transactional scope of the client's request and it may access SessionContext information specific to the client request: for example, the security and transactional methods. Once the instance has finished servicing the client, it is disassociated from the EJB object and returned to the Method-Ready Pool.
PostConstruct is invoked only once in the life cycle of an instance: when it is transitioning from the Does Not Exist state to the Method-Ready Pool. It is not reinvoked every time a client requests a remote reference to the bean.
The Stateful Session Bean
Each stateful session bean is dedicated to one client for the life of the bean instance; it acts on behalf of that client as its agent. Stateful session beans are not swapped among EJB objects nor are they kept in an instance pool, like stateless session bean instances are. Once a stateful session bean is instantiated and assigned to an EJB object, it is dedicated to that EJB object for its entire life cycle.
Stateful session beans maintain conversational state, which means that the instance variables of the bean class can maintain data specific to the client between method invocations. This makes it possible for methods to be interdependent so that changes made to the bean's state in one method call can affect the results of subsequent method invocations. Therefore, every method call from a client must be serviced by the same instance (at least conceptually), so the bean instance's state can be predicted from one method invocation to the next.
Stateful session beans allow you to encapsulate some of the business logic and conversational state of a client and move it to the server. Moving this logic to the server thins the client application and makes the system as a whole easier to manage. The stateful session bean acts as an agent for the client, managing processes or taskflow to accomplish a set of tasks;
@Remove TicketDO bookPassage(CreditCardDO card, double price) throws IncompleteConversationalState {}
The bookPassage( ) method is annotated with the @Remove annotation. The @Remove annotation tells the EJB container that when the method completes, the client no longer needs the session. After the bookPassage( ) method completes, the EJB container removes the session from the EJB container.
The TravelAgent EJB also provides transactional integrity for processing the customer's reservation. If any of the operations within the body of the bookPassage( ) method fails, all the operations are rolled back so that none of the changes is accepted. If the credit card cannot be charged by the ProcessPayment EJB, the newly created Reservation EJB and its associated record are not created.
The Life Cycle of a Stateful Session Bean
Stateful session beans are dedicated to one client for their entire lives, so swapping or pooling of instances isn't possible.[*] When they are idle, stateful session bean instances are simply evicted from memory. The EJB object remains connected to the client, but the bean instance is dereferenced and garbage-collected during inactive periods. This means that each stateful bean must be passivated before it is evicted in order to preserve the conversational state of the instance, and it must be activated to restore its state when the EJB object becomes active again.
The bean's perception of its life cycle depends on whether it implements a special interface called SessionSynchronization . This interface defines an additional set of callback methods that notify the bean of its participation in transactions. A bean that implements SessionSynchronization can cache database data across several method calls before making an update.
The life cycle of a stateful session bean has three states: Does Not Exist, Method-Ready, and Passivated.
A client application can remove a bean by invoking a business interface method annotated as @Remove .
The Passivated State
During the lifetime of a stateful session bean, there may be periods of inactivity when the bean instance is not servicing methods from the client. To conserve resources, the container can passivate the bean instance by preserving its conversational state and evicting the bean instance from memory. A bean's conversational state may consist of primitive values, objects that are serializable, and the following special types:
The types in this list (and their subtypes) are handled specially by the passivation mechanism. They do not need to be serializable; they will be maintained through passivation and restored automatically when the bean instance is activated.
When the client makes a request on an EJB object whose bean is passivated, the container activates the instance. This involves deserializing the bean instance and reconstructing the SessionContext reference, bean references, and managed resource factories held by the instance before it was passivated. When a bean's conversational state has been successfully restored, an @PostActivate callback method is invoked on the bean instance if one is declared on the bean class. The bean instance should open any resources that cannot be passivated and initialize the values of any transient fields within the @PostActivate method. Once @PostActivate is complete, the bean is back in the Method-Ready state and is available to service client requests delegated by the EJB object.
The activation of a bean instance follows the rules of Java serialization, regardless of how the bean's state was actually stored. The exception to this is transient fields.
EJB, transient fields can contain arbitrary values when the bean is activated. The values held by transient fields following activation are unpredictable across vendor implementations, so do not depend on them to be initialized. Instead, use an @PstActivate callback method to reset their values.
System exceptions
Whenever a system exception is thrown by a bean method, the container invalidates the EJB object and destroys the bean instance. The bean instance moves directly to the Does Not Exist state, and any @PreDestroy call methods are not invoked.
Stateful Session Beans and Extended Persistence Contexts
Stateful session beans are the only EJB component type that is allowed to inject an EXTENDED persistence context through the @PersistenceContext annotation. The extended persistence context is created and attached to the stateful bean instance before @PostConstruct . When the stateful bean instance is removed, the extended persistence context is also cleaned up. Because a stateful bean represents a conversation with a client, it makes sense to cache and manage entity instances across method invocations. Stateless and message-driven beans are pooled, and managed entity instances would easily become stale and unusable.
@Stateful class TravelAgentBean implements TravelAgentRemote {
@PersistenceContext(unitName="titan", type=EXTENDED) EntityManager entityManager;
When the persistence context type is marked as EXTENDED, queried entities will remain managed and attached to the stateful session bean's EntityManager. With this setting, the updateAddress( ) method can get a little simpler, as the EntityManager.merge( ) method is no longer needed. Any extended persistence context that a stateful bean has will automatically be registered with a transaction when any transactional method is invoked. When the updateAddress( ) method completes, the EJB container will automatically commit the state changes made to customer without having to manually call the merge( ) or flush( ) method.
Nested Stateful Session Beans
Stateful session beans behave in interesting ways when you inject other stateful session beans within them. When you inject a stateful session bean into an EJB with the @EJB annotation, a session is created for that injected instance.
When a stateful bean reference is injected into another stateful session bean, the containing bean owns the injected session. This means that when the containing bean is created, a unique session is created for the injected reference. When the containing bean is removed, the contained stateful bean is also removed. In the ShoppingCartBean example, an AnotherStatefulLocal session is created for the another member variable when an instance of it is created. When the checkout( ) method is called, another's stateful session is also removed. This feature of the specification allows you to cleanly aggregate conversational business processes without having to worry about managing the life cycle of the contained stateful sessions.
Nested stateful session beans also have an interesting effect when they inject an EXTENDED persistence context that also exists in the containing stateful bean. When this scenario happens, the containing and contained stateful session beans share the same EXTENDED persistence context.
Message-Driven Beans
JMS as a Resource
JMS is a vendor-neutral API that can be used to access enterprise messaging systems. Enterprise messaging systems (a.k.a. message-oriented middleware) facilitate the exchange of messages between software applications over a network.
ConnectionFactory and Topic
In order to send a JMS message, we need a connection to the JMS provider and a destination address for the message. A JMS connection factory makes the connection to the provider possible; the destination address is identified by a Topic object. Both the connection factory and the Topic object are obtained by using @javax.annotation.Resource to inject these objects directly into the fields.
@Resource(mappedName="ConnectionFactoryNameGoesHere") ConnectionFactory connectionFactory;
@Resource(mappedName="TicketTopic") Topic topic;
The Topic object itself represents a network-independent destination to which the message will be addressed. In JMS, messages aren't sent directly to applications; they're sent to topics or queues. A topic is analogous to an email list or newsgroup; any application with the proper credentials can receive messages from and send messages to a topic. When a JMS client receives messages from a topic, the client is said to subscribe to that topic. JMS decouples applications by allowing them to send messages to each other through a destination, which serves as a virtual channel. A queue is another type of destination.
Connection and Session
The ConnectionFactory is used to create a Connection, which is an actual connection to the JMS provider:
Connection connect = connectionFactory.createConnection( );
Session session = connect.createSession(true,0);
Once you have a Connection , you can use it to create a Session. A Session allows you to group the actions of sending and receiving messages. In this case, you need only a single Session. Using multiple Sessions is helpful if you wish to produce and consume messages in different threads. Session objects use a single-threaded model, which prohibits concurrent access to a single Session from multiple threads. The thread that creates a Session is usually the thread that uses that Session's producers and consumers (i.e., MessageProducer and MessageConsumer objects). If you wish to produce and consume messages using multithreading, you must create a different Session object for each thread.
The createSession( ) method has two parameters: createSession(boolean transacted, int acknowledgeMode)
According to the EJB specifications, these arguments are ignored at runtime because the EJB container manages the transaction and acknowledgment mode of any JMS resource obtained from the JNDI ENC. The specification recommends that developers use the arguments true for transacted and 0 for acknowledgeMode, but since they are supposed to be ignored, it should not matter what you use.
It's good programming practice to close a Connection after it has been used: connect.close( );
The Session is used to create a MessageProducer, which sends messages from the TravelAgent EJB to the destination specified by the Topic object. Any JMS clients that subscribe to that topic will receive a copy of the message:
MessageProducer producer = session.createProducer(topic);
TextMessage textMsg = session.createTextMessage( );
Message types
In JMS, a message is a Java object with two parts: a header and a message body. The header is composed of delivery information and metadata, and the message body carries the application data, which can take several forms: text, serializable objects, byte streams, etc. The JMS API defines several message types (TextMessage, MapMessage, ObjectMessage , and others) and provides methods for delivering messages to and receiving messages from other applications.
In addition to TextMessage, MapMessage, and ObjectMessage, JMS provides two other message types: StreamMessage and BytesMessage . StreamMessage can take the contents of an I/O stream as its payload. BytesMessage can take any array of bytes, which it treats as opaque data.
The MessageConsumer is designed to process incoming messages that are published to its Topic:
Session session = connect.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer(topic);
consumer.setMessageListener(this); connect.start( );
The MessageConsumer can receive messages directly or delegate message processing to a javax.jms.MessageListener .
MessageListener objects implement a single method, onMessage( ), which is invoked every time a new message is sent to the subscriber's topic.
JMS Is Asynchronous
One of the principal advantages of JMS messaging is that it's asynchronous. In other words, a JMS client can send a message without having to wait for a reply.
clients send messages asynchronously to a destination (topic or queue) from which other JMS clients can also receive messages. When a JMS client sends a message, it doesn't wait for a reply; it sends the message to a router, which is responsible for forwarding the message to other clients. There's no effect on the client if one or more recipients are unavailable; it just goes ahead with its work. It's the router's responsibility to make sure that the message eventually reaches its destination. Clients sending messages are decoupled from the clients receiving them; senders are not dependent on the availability of receivers.
The limitations of RMI make JMS an attractive alternative for communicating with other applications. Using the standard JNDI environment-naming context, an enterprise bean can obtain a JMS connection to a JMS provider and use it to deliver asynchronous messages to other Java applications.
Because messaging is inherently decoupled and asynchronous, the transactions and security contexts of the sender are not propagated to the receiver.
JMS Messaging Models
JMS provides two types of messaging models: publish-and-subscribe and point-to-point . The JMS specification refers to these as messaging domains. In JMS terminology, publish-and-subscribe and point-to-point are frequently shortened to pub/sub and p2p (or PTP), respectively.
In the simplest sense, publish-and-subscribe is intended for a one-to-many broadcast of messages, and point-to-point is intended for one-to-one delivery of messages.
In publish-and-subscribe messaging, one producer can send a message to many consumers through a virtual channel called a topic. Consumers can choose to subscribe to a topic. Any messages addressed to a topic are delivered to all the topic's consumers. The pub/sub messaging model is largely a push-based model , in which messages are automatically broadcast to consumers without the consumers having to request or poll the topic for new messages.
In the pub/sub messaging model, the producer sending the message is not dependent on the consumers receiving the message. JMS clients that use pub/sub can establish durable subscriptions that allow consumers to disconnect and later reconnect and collect messages that were published while they were disconnected.
The point-to-point messaging model allows JMS clients to send and receive messages both synchronously and asynchronously via virtual channels known as queues. The p2p messaging model has traditionally been a pull- or polling-based model, in which messages are requested from the queue instead of being pushed to the client automatically.[*] A queue may have multiple receivers, but only one receiver may receive each message.
In most cases, the decision about which model to use depends on which model is a better fit for the application. With pub/sub, any number of subscribers can be listening on a topic, and all of them will receive copies of the same message. The publisher may not care if everybody is listening, or even if nobody is listening.
In contrast, a point-to-point session is likely to be intended for a one-on-one conversation with a specific application at the other end. In this scenario, every message really matters. The range and variety of the data the messages represent can be a factor as well. Using pub/sub, messages are dispatched to the consumers based on filtering that is provided through the use of specific topics. Even when messaging is being used to establish a one-on-one conversation with another known application, it can be advantageous to use pub/sub with multiple topics to segregate different kinds of messages. Each kind of message can be dealt with separately through its own unique consumer and onMessage( ) listener.
Point-to-point is more convenient when you want a particular receiver to process a given message once. This is perhaps the most critical difference between the two models: p2p guarantees that only one consumer processes each message. This ability is extremely important when messages need to be processed separately but in tandem.
Session Beans Should Not Receive Messages
it is dangerous because a call to the MessageConsumer.receive( ) method blocks the thread until a message becomes available. If a message is never delivered, the thread is blocked indefinitely! If no one ever sends a message to the queue, the MessageConsumer just sits there waiting, forever.
To be fair, there are other receive( ) methods that are less dangerous. For example, receive(long timeout) allows you to specify a time after which the MessageConsumer should stop blocking the thread and give up waiting for a message. There is also receiveNoWait( ), which checks for a message and returns null if none is waiting, thus avoiding a prolonged thread block. However, this operation is still dangerous. There is no guarantee that the less risky receive( ) methods will perform as expected, and the risk of programmer error (e.g., using the wrong receive( ) method) is too great.
The moral of the story is simple: don't write convoluted code trying to force session beans to receive messages. If you need to receive messages, use a message-driven bean; MDBs are specially designed to consume JMS messages.
JMS-Based Message-Driven Beans
Message-driven beans (MDBs) are stateless, server-side, transaction-aware components for processing asynchronous messages delivered via JMS. While a message-driven bean is responsible for processing messages, its container manages the component's environment, including transactions, security, resources, concurrency, and message acknowledgment.
While a message-driven bean has a bean class, it does not have a remote or local business interface.
@MessageDriven(activationConfig={@ActivationConfigProperty( propertyName="destinationType", propertyValue="javax.jms.Queue"), @ActivationConfigProperty( propertyName="messageSelector", propertyValue="MessageFormat = 'Version 3.4'"), @ActivationConfigProperty( propertyName="acknowledgeMode",
propertyValue="Auto-acknowledge")}) class ReservationProcessorBean implements javax.jms.MessageListener {
@PersistenceContext(unitName="titanDB") EntityManager em;
@EJB ProcessPaymentLocal process;
@Resource(mappedName="ConnectionFactory") ConnectionFactory connectionFactory;
void onMessage(Message message) {}
Message-driven beans also have a context object that is similar in functionality to that of the SessionContext.
This object may be injected using the @javax.annotation.Resource annotation:
@Resource MessageDrivenContext context;
The MessageDrivenContext simply extends the EJBContext ; it does not add any new methods.
MessageListener interface
Sending messages from a message-driven bean
Queue queue = (Queue)reservationMsg.getJMSReplyTo( );
Connection connect = connectionFactory.createConnection( );
Session session = connect.createSession(true,0);
MessageProducer sender = session.createProducer(queue);
ObjectMessage message = session.createObjectMessage( ); message.setObject(ticket);
sender.send(message); connect.close( );
Every message type has two parts: a message header and a message body (a.k.a. the payload). The message header contains routing information and may also have properties for message filtering and other attributes. One of these attributes may be JMSReplyTo . The message's sender may set the JMSReplyTo attribute to any destination accessible to its JMS provider.
Because MDBs can receive messages from arbitrary messaging providers, the configuration must be very flexible to be able to describe the proprietary properties that different providers will have. JCA-based MDBs don't necessarily use JMS as the message service, so this requirement is very important. To facilitate this, the @MessageDriven.activationConfig( ) attribute takes an array of @ActivationConfigProperty annotations. These annotations are simply a set of name/value pairs that describe the configuration of your MDB.
The property names and values used in the activationConfig( ) attribute to describe the messaging service vary depending on the type of message service used, but EJB 3.0 defines a set of fixed properties for JMS-based message-driven beans. These properties are acknowledgeMode, messageSelector, destinationType, and subscriptionDurability .
Message selector
An MDB can declare a message selector . Message selectors allow an MDB to be more selective about the messages it receives from a particular topic or queue. Message selectors use Message properties as criteria in conditional expressions.[*] These conditional expressions use Boolean logic to declare which messages should be delivered.
Here's how a JMS producer would go about setting a MessageFormat property on a Message:
Message message = session.createMapMessage( ); // set the reservation named values
message.setStringProperty("MessageFormat","Version 3.4"); sender.send(message);
Acknowledge mode
Two values can be specified for acknowledgment mode: Auto-acknowledge and Dups-ok-acknowledge . Auto-acknowledge tells the container that it should send an acknowledgment to the JMS provider soon after the message is given to an MDB instance to process. Dups-ok-acknowledge tells the container that it doesn't have to send the acknowledgment immediately; anytime after the message is given to the MDB instance will be fine. With Dups-ok-acknowledge , it's possible for the MDB container to delay acknowledgment for so long that the JMS provider assumes the message was not received and sends a "duplicate" message. Obviously, with Dups-ok-acknowledge, your MDBs must be able to handle duplicate messages correctly.
Subscription durability
When a JMS-based MDB uses a javax.jms.Topic , the deployment descriptor must declare whether the subscription is Durable or NonDurable . A Durable subscription outlasts an MDB container's connection to the JMS provider, so if the EJB server suffers a partial failure, shuts down, or otherwise disconnects from the JMS provider, the messages that it would have received are not lost. The provider stores any messages that are delivered while the container is disconnected; the messages are delivered to the container (and from there to the MDB) when the container reconnects. This behavior is commonly referred to as store-and-forward messaging. Durable MDBs are tolerant of disconnections, whether intentional or the result of a partial failure.
If the subscription is NonDurable, any messages the bean would have received while it was disconnected are lost. Developers use NonDurable subscriptions when it is not critical for all messages to be processed. Using a NonDurable subscription improves the performance of the JMS provider but significantly reduces the reliability of the MDBs.
When the destination type is javax.jms.Queue , as is the case in the ReservationProcessor EJB, durability is not a factor because of the nature of queue-based messaging systems. With a queue, messages may be consumed only once and they remain in the queue until they are distributed to one of the queue's listeners.
The Life Cycle of a Message-Driven Bean
Connector-Based Message-Driven Beans
Although the JMS-based MDB has proven very useful, it has limitations. Perhaps the most glaring limitation is that EJB vendors are able to support only a small number of JMS providers (usually only one).
Connector-Based Message-Driven Beans
Message Linking
The EJB specification does not have an annotation to wire message linking, so we'll have to create a partial XML deployment descriptor to enable this feature. In order to link the outgoing messages sent by the TravelAgent EJB with the incoming messages consumed and processed by the TicketDistribution MDB, we need to define <message-destination-link> elements in the deployment descriptor. The <message-destination-link> element is defined by the <message-destination-ref> element of the TravelAgent EJB. The TicketDistributor EJB also declares the <message-destination-link> element. Both elements reference the same logical destination declared in the assembly descriptor.
A <message-destination-ref> element declares the destination to which an enterprise bean sends or receives messages. When the <message-destination-ref> includes a <message-destination-link> element, it means that message senders and receivers will be sharing a logical destination described in the assembly descriptor.
Timer Service
The Timer Service is a facility of the EJB container system that provides a timed-event API, which can be used to schedule timers for specified dates, periods, and intervals. A timer is associated with the enterprise bean that set it, and it calls that bean's ejbTimeout( ) method or a method annotated with @Timeout when it goes off.
Timer Service API
The Timer Service enables an enterprise bean to be notified when a specific date has arrived, when some period of time has elapsed, or at recurring intervals. To use the Timer Service, an enterprise bean must implement the TimedObject interface, which defines a single callback method, void ejbTimeout(Timer timer)( ).
In EJB 3.0, the @Timeout annotation can be applied to a method whose signature returns void and has one Timer parameter.
@Stateless class ShipMaintenanceBean implement ShipMaintenanceRemote {
@Timeout void maintenance(Timer timer) {}}
An enterprise bean schedules itself for a timed notification using a reference to the TimerService , which can be obtained from the EJBContext or injected directly into your bean using the @javax.annotation.Resource annotation. The TimerService allows a bean to register itself for notification on a specific date, after some period of time, or at recurring intervals.
scheduleMaintenance{String item = ship + " is scheduling maintenance of " + description;
timerService.createTimer(dateOf, msg);}
@Timeout void maintenance(Timer timer) {String item = (String)timer.getInfo( );}
The TimerService Interface
There are essentially two types of timers: single-action and interval. When a timer is created, the Timer Service makes it persistent in some type of secondary storage, so it will survive system failures. If the server goes down, the timers are still active when the server comes back up. While the specification isn't clear, it's assumed that any timers that expire while the system is down will go off when it comes back up again.
The Timer
A Timer is an object that implements the Timer interface. It represents a timed event that has been scheduled for an enterprise bean using the Timer Service. Timer objects are returned by the TimerService.createTimer( ) and TimerService.getTimers( ) methods, and a Timer is the only parameter of the TimedObject.ejbTimeout( ) method or annotated @Timeout callback.
Serializable getInfo( ); void cancel( ); java.util.Date getNextTimeout( ), long getTimeRemaining( )
Identifying timers
All of the TimeService.createTimer( ) methods declare an info object as their last parameter. The info object is application data that is stored by the Timer Service and delivered to the enterprise bean when its timeout callback is invoked.
The TimerHandle object
The Timer.getHandle( ) method returns a TimerHandle object. The TimerHandle object is similar to the Handle and HomeHandle. It's a reference that can be saved to a file or some other resource and then used later to regain access to the Timer.
Timer getTimer( ) throws NoSuchObjectLocalException, EJBException;
When a bean calls createTimer( ), the operation is performed in the scope of the current transaction. If the transaction rolls back, the timer is undone: it's not created (or, more precisely, it's uncreated).
The JNDI ENC and Injection
Every EJB container that is deployed in an application server has its own personal internal registry called the Enterprise Naming Context (ENC). This ENC is implemented by JNDI and is a sandbox where the EJB container can hold specific references to its environment.
The JNDI ENC
Developers could define aliases to resources, EJBs, and environment entries in the JNDI ENC through EJB XML deployment descriptors.
What Can Be Registered in the JNDI ENC?
Many different items can be bound to the ENC: references to any EJB interface, a JMS queue or topic destination, JMS connection factories, data sources, any JCA resource, and even primitive values. Java EE services such as javax.transaction.UserTransaction, TimerService, and org.omg.CORBA.ORB are also available in the ENC.
How Is the JNDI ENC Populated?
The ENC's JNDI namespace is populated in two separate ways: via XML or via annotations. Any reference that you declare in XML to a service or resource automatically populates the JNDI ENC with the reference's name. Any environment annotation that you use in your bean class also causes the ENC to be populated. Once an item is bound to the JNDI ENC of the EJB container, it can be referenced by a JNDI lookup.
XML Population
<session> <ejb-local-ref> <ejb-ref-name>ejb/ProcessPayment </ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type> <local>com.titan.processpayment.ProcessPaymentLocal</local>
<ejb-link>ProcessPaymentBean</ejb-link> </ejb-local-ref><session>
The <ejb-local-ref> element tells the EJB container that the travelAgentBean wants a reference to the ProcessPayment EJB. A reference to this bean is registered in the travelAgentBean's JNDI ENC under the name ejb/ProcessPayment. This is defined by the <ejb-ref-name> element. Other referenceable things, like resources and JMS destinations, have similar XML elements such as <ejb-local-ref> to specify how and where the reference will be bound into their JNDI ENCs.
Annotation Population
@Stateful @EJB(name="ejb/ProcessPayment", beanInterface=ProcessPaymentLocal.class, beanName="ProcessPaymentBean") class TravelAgentBean implements TravelAgentRemote {}
We are registering a reference to the ProcessPayment EJB under the ejb/ProcessPayment name. Business logic running inside the travelAgentBean is able to do JNDI lookups to find this reference. Each environment annotation, such as @javax.annotation.EJB , has a name( ) attribute that specifies the JNDI ENC name to which you want the service reference to be bound.
How Are Things Referenced from the ENC?
Anything registered in the JNDI ENC can be looked up by name under the java:comp/env context. The comp part of this name corresponds to component. The JNDI name resolves to a different context depending on where you invoke the lookup. For example, if you invoke jndi.lookup("java:comp/env") within the travelAgentBean, you will get that EJB container's ENC. If you do the same within ProcessPaymentBean, you will get a different ENC registry specific to that bean. The application server knows what ENC is active when you perform the lookup.
ProcessPaymentLocal payment = (ProcessPaymentLocal) ctx.lookup("java:comp/env/ejb/ProcessPayment");
payment.process(card, customer, amount);
The code needs a reference to the ProcessPayment EJB so that it can bill the customer for the reservation. A reference to the ProcessPayment EJB was created in the TravelAgent's ENC by annotating the bean class with the @EJB annotation. The preceding code does a JNDI lookup to find this reference. While the ProcessPayment.process( ) method is invoked, the java:comp/env/ejb/ProcessPayment reference is no longer available because the ProcessPayment's ENC is active instead of the TravelAgent's ENC.
Using EJBContext
The EJBContext interface has a convenience ENC lookup method. This method is a bit simpler than a direct JNDI lookup because it does not throw a checked exception and it takes a relative name into the ENC instead of the full java:comp/env string we saw before. SessionContext or MessageDrivenContext can be injected into your session or message-driven beans by using the @javax.annotation.Resource annotation.
@Stateful @EJB(name="ejb/ProcessPayment", beanInterface=ProcessPaymentLocal.class, beanName="ProcessPaymentBean") class TravelAgentBean implements TravelAgentRemote {
@Resource SessionContext ejbContext;
ProcessPaymentLocal payment = (ProcessPaymentLocal) ejbContext.lookup("ejb/ProcessPayment");
payment.process(card, customer, amount);
Annotation injection
Instead of an ENC lookup, the ProcessPayment EJB reference can be injected directly into a member variable of the TravelAgent EJB. This injection can be done through environment annotations or an XML deployment descriptor fragment.
@EJB ProcessPaymentLocal payment;
@EJB void setProcessPayment(ProcessPaymentLocal payment) {}
By using the @EJB annotation on the payment field of the travelAgentBean class, the EJB container will automatically inject a reference to the ProcessPayment EJB directly into the payment field when the travelAgent bean instance is created.
Default ENC name
Annotating a field or a setter method of a bean class also creates an entry in the JNDI ENC for the injected element.If the name( ) attribute of the injection annotation is specified, then the reference is stored in the ENC under that name. If no name is specified, then the ENC name is extracted from the name of the annotated field or setter method. In this case, a default ENC name is derived from the fully qualified class name of the field or method, as well as the base name of the field or method. So, for the payment field of the previous example, the ENC name would be com.titan.travelagent.TravelAgentBean/payment . For the setProcessPayment( ) method, the default ENC name would be com.titan.travelagent.TravelAgentBean/processPayment . These injected EJB references can then be looked up in JNDI under java:comp/env/com.titan.travelagent.TravelAgentBean/payment and java:comp/env/com.titan.travelagent.TravelAgentBean/processPayment , respectively. The ENC name becomes very important when you want to override an injection annotation within XML.
Reference and Injection Types
EJB References
EJB bean classes can reference and aggregate other EJBs either through JNDI ENC lookups or by directly injecting these references into member fields.
@EJB(name="ejb/ProcessPayment", beanInterface=ProcessPaymentLocal.class)
class TravelAgentBean implements TravelAgentRemote {}
The name( ) attribute refers to what the JNDI ENC name will be for the referenced EJB. This name is relative to the java:comp/env context.
The beanInterface( ) attribute is the interface you are interested in and usually is used by the container to distinguish whether you want a remote or local reference to the EJB.
The beanName( ) is the EJB name of the EJB referenced. It is equal to either the value you specify in the @Stateless.name( ) or @Stateful.name( ) annotation, or the value you put in the <ejb-name> field in the XML deployment descriptor.
The mappedName( ) attribute is a placeholder for a vendor-specific identifier. This identifier may be a key into the vendor's global registry. Many vendors store references to EJBs within the global JNDI tree so that clients can reference them, and mappedName( ) may reference that global JNDI name.
Object ref = jndiContext.lookup("java:comp/env/ejb/ProcessPayment");
ProcessPaymentLocal local = (ProcessPaymentLocal)ref;
When the @EJB annotation is used on the bean class, the name( ) and beanInterface( ) attributes are required. Most of the time, only the bean's interface is needed to distinguish which EJB you are referring to. Sometimes, though, you may be reusing the same business interface for multiple deployed EJBs. In that case, the beanName( ) or mappedName( ) attribute must be used to provide a unique identifier for the EJB you want to reference.
The @EJB annotation can be used only once on your bean class. When you need to reference multiple EJBs, the @EJBs annotation is available.
@EJBs({@EJB (name="ProcessPayment", beanInterface=ProcessPaymentLocal.class),@EJB(name="CustomerReferralEngine", beanInterface=CustomerReferralLocal.class)})
The @EJB annotation can also be placed on a setter method or member field so that the EJB referenced will be injected directly into the bean class instance.
XML-based remote EJB references
The <ejb-ref> element can be linked directly to a specific EJB container by using the <ejb-link> element. This element is equivalent in description to the beanName( ) attribute of the @EJB annotation. It references the EJB-name of the referenced EJB. The EJB linked can be in the same JAR deployment as the referencing EJB, or in another deployment within an Enterprise ARchive (.ear)
The <injection-target> element is used if you want to inject the EJB reference into a field or setter method of your bean class.
<session> <ejb-ref>
<ejb-ref-name>ejb/ProcessPaymentRemote </ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type>
<injection-target> </injection-target> </ejb-ref> </session>
Ambiguous and overloaded EJB names
The <ejb-name> element and any @Stateless.name( ) or @Stateful.name( ) attributes must be unique within a given EJB JAR deployment. Unfortunately, this is not the case for all EJB JARs deployed in an Enterprise ARchive. In an .ear file, EJB names can be duplicated in different EJB-JAR deployments. To differentiate references with duplicate EJB names, the EJB specification has an extended syntax for <ejb-link> and the beanName( ) attribute of the @EJB annotation. This extended syntax has a relative path to the JAR file in which the EJB is located, followed by the # character, followed by the EJB name of the referenced bean:
@EJB(beanName="inventory-ejb.jar#InventoryEJB") InventoryLocal inventory;
Resolving EJB references
@EJB ProcessPaymentLocal processPayment;
Let's see how the JBoss application server resolves this reference:
The only possible identifier for this EJB reference is the business interface type. The application server first looks for a unique EJB in the referencing EJB's EJB-JAR deployment that uses ProcessPaymentLocal as its local or remote interface. If more than one EJB uses the same business interface, it throws a deployment exception.
If the EJB-JAR is deployed as part of an Enterprise ARchive (.ear), it looks in other EJB-JARs for a unique EJB that uses the ProcessPaymentLocal interface. Again, if more than one EJB uses the same business interface, it throws a deployment exception.
If the EJB reference is not found in the .ear file, it looks for it in other global EJB-JAR deployments.
If the beanName( ) attribute is specified, then JBoss uses the same search process, but it uses the beanName( )'s value as an additional identifier.
If the mappedName( ) attribute is specified, then no search process is performed. The application server expects that a specific EJB is bound into the global JNDI under the mappedName( )'s value.
EntityManagerFactory References
@PersistenceUnit(name="persistence/TitanDB", unitName="TitanDB")
The name( ) attribute refers to what the JNDI ENC name will be for the referenced EntityManagerFactory. This name is relative to the java:comp/env context.
The unitName( ) attribute identifies which EntityManagerFactory you are interested in referencing and refers to the name you have given your persistence unit that you declared in a persistence.xml file. If left unspecified, a deployment error is raised unless the EJB-JAR has only one persistence unit deployed within it. In that case, it defaults to this sole persistence unit.
EntityManagerFactory titan = (EntityManagerFactory) jndiContext.lookup("java:comp/env/persistence/TitanDB");
The @PersistenceUnit annotation can be used only once on your bean class. When you need to reference multiple persistence units, use @PersistenceUnits annotation.
Scoped and overloaded unit names
@PersistenceUnit(unitName="inventory.jar#InventoryDB") EntityManagerFactory inventory;
EntityManager References
@PersistenceContext and @PersistenceContexts
The type( ) attribute specifies the type of persistence context you want. PersistenceContextType.TRANSACTION specifies that you want a transaction-scoped persistence context. This is the default. PersistenceContextType.EXTENDED gives you an extended persistence context. The EXTENDED type can be used only on stateful session beans. You will receive a deployment error if you use it with any other bean type.
The properties( ) attribute allows you to pass in additional vendor-specific properties for the created EntityManager instance. You set this attribute with an array of @PersistenceProperty annotation declarations.
@PersistenceContext(unitName="crmDB") EntityManager crm;
Scoped and overloaded unit names
@PersistenceContext(unitName="inventory.jar#InventoryDB") EntityManager inventory;
Resource References
External resources can be of the type javax.sql.DataSource, javax.jms.Connection-Factory, javax.jms.QueueConnectionFactory, javax.jms.TopicConnectionFactory, javax.mail.Session, java.net.URL , or javax.resource.cci.ConnectionFactory , or any other type defined by a JCA resource adapter.
@javax.annotation.Resource and @Resources
The type( ) attribute declares the fully qualified class name of the resource's Java type. When the @Resource annotation is applied to the bean class, this attribute may be important to the EJB container to truly identify the resource in which you are interested. Usually, this attribute is unneeded and the default value is good enough.
The mappedName( ) attribute is a vendor-specific identifier for the external resource. Since Java EE has no specified mechanism or global registry for finding global resources, many vendors require this attribute so that they can locate and bind the resource. Many times, this mappedName( ) attribute will be equivalent to a global JNDI name.
The authenticationType( ) attribute tells the server who is responsible for authentication when the resource is accessed. It can have one of two values: CONTAINER or APPLICATION . If CONTAINER is specified, the container will automatically perform authentication (sign on or log in) to use the resource, as specified at deployment time. If APPLICATION is specified, the bean itself must perform the authentication before using the resource.
@Resource(mappedName="java:/DefaultDS") javax.sql.DataSource oracle;
When used on a setter method or member field, only the mappedName( ) attribute may be required to identify the resource, as the type and ENC name can be determined from the type and name of the method or field.
Resource Environment and Administered Objects
Resource environment entries are objects that do not fall into the resource reference category. Some resources may have other, additional administered objects that need to be obtained from the JNDI ENC or injected into your bean class. An administered object is a resource that is configured at deployment time and is managed by the EJB container at runtime. They are usually defined and deployed by a JCA resource adapter.
Besides administered objects, resource environment entries are also used to reference services such as javax.transaction.UserTransaction and javax.transaction.TransactionSynchronizationRegistry .
@Resource javax.transaction.UserTransaction utx;
<session> <resource-env-ref>
<resource-env-ref-type>javax.transaction.UserTransaction </resource-env-ref-type>
<injection-target> </injection-target> </resource-env-ref> </session>
Environment Entries
@Resource(name="minCheckNumber") int minCheckNumber = 100;
Although they can be defined using annotations, environment entries are almost always configured via XML, as they really are configuration values and not metadata. The <env-entry> element is used to define them.
<session> <env-entry>
<env-entry-type>java.lang.Integer</env-entry-type> <env-entry-value>2000</env-entry-value>
</env-entry> </session>
Message Destination References
@Resource(mappedName="topic/TicketTopic") javax.jms.Topic ticketTopic;
Web Service References
Web service references populate the JNDI ENC with a pointer to either the service interface or the service endpoint interface. The wsdlLocation( ) attribute is used to define the location of the WSDL file. You can usually leave this empty, and the deployer will generate or locate it for you automatically. When referencing a service endpoint directly, the value( ) attribute can be filled with the class of the service interface from which to obtain the endpoint.
Using @javax.xml.ws.WebServiceRef
@WebServiceRef ProcessorService service;
@WebServiceRef(ProcessorService.class) Processor endpoint;
Interceptors are objects that are able to interpose themselves on method calls or the life cycle events of session and message-driven beans. They allow you to encapsulate common behavior that cuts across large parts of your application. This behavior is usually common code that you don't want to pollute your business logic.
Intercepting Methods
Interceptor Class
Object <any-method-name>(InvocationContext invocation) throws Exception;
@AroundInvoke method wraps around the call to your business method and is actually invoked in the same Java call stack and in the same transaction and security context as the bean method it is intercepting. The InvocationContext parameter is a generic representation of the business method the client is invoking. You can obtain information such as the target bean instance on which you are invoking, access to its parameters expressed as an array of objects, and a reference to a java.lang.reflect.Method object that is the generic representation of the actual invoked method. InvocationContext is also used to drive the invocation.
Applying Interceptors
The @Interceptors annotation can be used to apply interceptors to individual methods or to every method in the EJB's bean class.
Default interceptors
<ejb-name> element in an <interceptor-binding> can take a wildcard. In this case, you are applying one or more interceptors that you declare in the interceptor-binding to every EJB in that particular JAR file deployment.
<assembly-descriptor> <interceptor-binding>
<ejb-name>*</ejb-name> <interceptor-class>com.titan.Profiler</interceptor-class>
</interceptor-binding> </assembly-descriptor>
Disabling interceptors
If you are using default interceptors or class-level interceptors, there may be times when you want to disable them for a particular EJB or for a particular method of an EJB. We can turn off all default interceptors by using the @ExcludeDefaultInterceptors annotation.
<interceptor-binding> <ejb-name>TravelAgentBean</ejb-name>
<exclude-default-interceptors/> <interceptor-class>com.titan.SomeOtherInterceptor</interceptor-class>
The same overriding and disabling of interceptors can be done at the method level as well. You can turn off interceptors entirely for a particular method by using the @ExcludeDefaultInterceptors and @ExcludeClassInterceptors annotations.
<exclude-default-interceptors/> <exclude-class-interceptors/>
Interceptors and Injection
Interceptors belong to the same ENC as the EJBs they intercept. Like the EJBs they intercept, interceptor classes have full support for all the injection annotations, as well as injection through XML.
Intercepting Life Cycle Events
Not only can you intercept EJB method invocations, but you can also intercept EJB life cycle events. These callbacks can be used to initialize the state of your EJB bean classes, as well as the interceptor class itself.
@<callback-annotation> void <method-name>(InvocationContext ctx);
Interceptor Life Cycle
Interceptor classes have the same life cycles as the EJBs they intercept. Consider an interceptor class as an extension of the EJB's bean instance. They are created along with bean instances. They are destroyed, passivated, and activated along with their bean instances as well. Also, it is important to note that interceptor classes have the same restrictions as the beans to which they are attached.
Bean Class @AroundInvoke Methods
When used inside a bean class, the @AroundInvoke method will be the last "interceptor" to be invoked before the actual bean method.
ACID Transactions
An atomic transaction must execute completely or not at all. This means that every task within a unit-of-work must execute without error. If any of the tasks fail, the entire unit-of-work or transaction is aborted, meaning that any changes to the data are undone.
Consistency refers to the integrity of the underlying data store.
Isolation means that a transaction must be allowed to execute without interference from other processes or transactions. In other words, the data that a transaction accesses cannot be affected by any other part of the system until the transaction or unit-of-work is completed.
Durability means that all the data changes made during the course of a transaction must be written to some type of physical storage before the transaction is successfully completed. This ensures that the changes are not lost if the system crashes.
Declarative Transaction Management
One of the primary advantages of Enterprise JavaBeans is that it allows for declarative transaction management . Without this feature, transactions must be controlled using explicit transaction demarcation, which involves the use of fairly complex APIs like the OMG's Object Transaction Service (OTS) or its Java implementation, the Java Transaction Service (JTS). At best, explicit demarcation is difficult if you use the aforementioned APIs, particularly if you are new to transactional systems. In addition, it requires that the transactional code be written within the business logic, which reduces the clarity of the code.
Transaction Scope
A transaction is propagated to an EJB when that EJB's method is invoked and included in the scope of that transaction. The transaction is also propagated to the persistence context of an EntityManager. The persistence context keeps track of changes made to persistent managed objects and commits them if the transaction succeeds.
Using the @TransactionAttribute annotation
The @transactionAttribute can be applied per method, or you can use it on the bean class to define the default transaction attribute for the entire bean class.
If you do not specify any @transactionAttribute and there is no XML deployment descriptor, the default transaction attribute will be REQUIRED. One of the ideas behind EJB 3.0 is to provide common defaults so that you do not have to be explicit about transaction demarcation. In the majority of cases, EJB methods will be transactional, especially if they are interacting with an entity manager.
Transaction attributes defined NotSupported, Supports, Required, RequiresNew, Mandatory, Never.
EJB 3.0 persistence and transaction attributes
The EJB specification strongly advises that EntityManagers be accessed within the scope of a JTA transaction. So, if you are wrapping access to your persistent entities with EJBs, use only the Required, RequiresNew, and Mandatory transaction attributes.
Message-driven beans and transaction attributes
Message-driven beans may declare only the NotSupported or Required transaction attribute. The other transaction attributes don't make sense in message-driven beans because they apply to client-initiated transactions.
A distributed transaction requires what is called a two-phase commit (2-PC or TPC). A 2-PC allows transactions to be managed across different servers and resources (e.g., databases and JMS providers).
Dirty, Repeatable, and Phantom Reads
Dirty reads
A dirty read occurs when a transaction reads uncommitted changes made by a previous transaction. If the first transaction is rolled back, the data read by the second transaction becomes invalid because the rollback undoes the changes. The second transaction will not be aware that the data it has read has become invalid.
Repeatable reads
A repeatable read occurs when the data read is guaranteed to look the same if read again during the same transaction. Repeatable reads are guaranteed in one of two ways: either the data read is locked against changes, or it is a snapshot that doesn't reflect changes. If the data is locked, it cannot be changed by any other transaction until the current transaction ends. If the data is a snapshot, other transactions can change the data, but these changes will not be seen by this transaction if the read is repeated.
Phantom reads
A phantom read occurs when new records added to the database are detectable by transactions that started prior to the insert. Queries will include records added by other transactions after their transaction has started.
Database Locks
The most common are read locks, write locks, and exclusive write locks.
The four types of locks are:
Read locks
Read locks prevent other transactions from changing data read during a transaction until the transaction ends, thus preventing nonrepeatable reads. Other transactions can read the data but not write to it. The current transaction is also prohibited from making changes. Whether a read lock locks only the records read, a block of records, or a whole table depends on the database being used.
Write locks
Write locks are used for updates. A write lock prevents other transactions from changing the data until the current transaction is complete but allows dirty reads by other transactions and by the current transaction itself. In other words, the transaction can read its own uncommitted changes.
Exclusive write locks
Exclusive write locks are used for updates. An exclusive write lock prevents other transactions from reading or changing the data until the current transaction is complete. It also prevents dirty reads by other transactions. Some databases do not allow transactions to read their own data while it is exclusively locked.
A snapshot is a frozen view of the data that is taken when a transaction begins. Some databases get around locking by providing every transaction with its own snapshot. Snapshots can prevent dirty reads, nonrepeatable reads, and phantom reads. They can be problematic because the data is not real-time data; it is old the instant the snapshot is taken.
Transaction Isolation Levels
Transaction isolation is defined in terms of the isolation conditions (dirty reads, repeatable reads, and phantom reads).
Read Uncommitted
The transaction can read uncommitted data (i.e., data changed by a different transaction that is still in progress). Dirty reads, nonrepeatable reads, and phantom reads can occur. Bean methods with this isolation level can read uncommitted changes.
Read Committed
The transaction cannot read uncommitted data; data that is being changed by a different transaction cannot be read. Dirty reads are prevented; nonrepeatable reads and phantom reads can occur. Bean methods with this isolation level cannot read uncommitted data.
Repeatable Read
The transaction cannot change data that is being read by a different transaction. Dirty reads and nonrepeatable reads are prevented; phantom reads can occur. Bean methods with this isolation level have the same restrictions as those in the Read Committed level and can execute only repeatable reads.
The transaction has exclusive read and update privileges; different transactions can neither read nor write to the same data. Dirty reads, nonrepeatable reads, and phantom reads are prevented. This isolation level is the most restrictive.
Controlling isolation levels
Bean-managed transactions in session beans and message-driven beans, however, allow you to specify the transaction isolation level using the database's API.
DataSource source = (javax.sql.DataSource) jndiCntxt.lookup("java:comp/env/jdbc/titanDB");
Connection con = source.getConnection( );
Optimistic Locking
@Version protected long getVersion( ) { return version;}
Whenever the entity class is updated, the version column is incremented. When a transaction beginning the commit process and business logic has updated the entity, the entity manager first checks to see if the version property of the in-memory entity instance matches the version column currently stored in the database. If the versions match, then the version property is incremented. If they don't match, then the entity manager throws an exception and the whole transaction rolls back.
Programmatic Locking
The EntityManager interface has a specific lock( ) method for performing entity locks. To use it, you pass in the entity object you want to lock and indicate whether you want a read or write lock: void lock(Object entity, LockModeType type);
UserTransaction tran = (UserTransaction) jndiCntx.lookup("java:comp/UserTransaction");
utx.begin( ); utx.commit( );
Enterprise beans can also manage transactions explicitly. Only session beans and message-driven beans that define a TransactionManagementType of Bean using the @TransactionManager annotation can manage their own transactions. Enterprise beans that manage their own transactions are frequently referred to as bean-managed transaction (BMT) beans.
@Stateless @TransactionManagement(TransactionManagerType.BEAN)
class HypotheticalBean implements HypotheticalLocal {
void someMethod( ) {
try { UserTransaction ut = ejbContext.getUserTransaction( );
ut.begin( ); ut.commit( );}
Alternatively, the UserTransaction can be injected directly into the bean:
@Resource UserTransaction ut;
An enterprise bean can also access the UserTransaction from the JNDI ENC.
UserTransaction tran = (UserTransaction) jndiCntx.lookup("java:comp/env/UserTransaction");
begin( )
Invoking the begin( ) method creates a new transaction. The thread that executes the begin( ) method is immediately associated with the new transaction, which is then propagated to any EJB that supports existing transactions.
SetRollbackOnly( )
The setRollbackOnly( ) method is invoked to mark the transaction for rollback. This means that, regardless of whether the updates executed within the transaction succeed, the transaction must be rolled back when completed.
Exceptions and Transactions
Application Exceptions Versus System Exceptions
System exceptions include java.lang.RuntimeException and its subclasses. System exceptions always cause a transaction to roll back when they are thrown from an enterprise bean method.
The container handles system exceptions automatically and it will always do the following:
Roll back the transaction; Log the exception to alert the system administrator; Discard the EJB instance.
The impact of discarding an EJB instance depends on the enterprise bean's type. In the case of stateless session beans, the client does not notice that the instance has been discarded. These instance types are not dedicated to a particular client; they are swapped in and out of an instance pool, so any instance can service a new request. With stateful session beans, however, the impact on the client is severe. Stateful session beans are dedicated to a single client and maintain conversational state. Discarding a stateful bean instance destroys the instance's conversational state and invalidates the client's reference to the EJB. When stateful session instances are discarded, subsequent invocations of the EJB's methods by the client result in a NoSuchEJBException.
Application exceptions
Application exceptions are always delivered directly to the client without being repackaged as an EJBException type. By default, they do not cause a transaction to roll back.
The @ApplicationException annotation may be used to force an application exception to roll back the transaction automatically.
@ApplicationException(rollback=true) class PaymentException extends java.lang.Exception{}
Transactional Stateful Session Beans
If the stateful bean implements SessionSynchronization , it can cache the items and write them to the database only when the transaction is complete.
The SessionSynchronization interface allows a session bean to receive additional notification of the session's involvement in transactions. The addition of these transaction callback methods by the SessionSynchronization interface expands the EJB's awareness of its life cycle to include a new state, the Transactional Method-Ready state .
Authentication, Authorization
For EJB applications, the user can be authorized on a per-method basis.
Confidentiality and integrity protection
When a user is interacting with an application over a network through a browser or through remote EJB invocations, it is possible for rogue individuals to intercept network packets and interpret the data if the connection is not secured. Data transfer should be protected and attackers should not be able to read or modify this data in transit. Data transfer can be secured through cryptographic services such as SSL.
Only session beans can be secured in EJB land.
When invoking on a remote EJB, many application servers accomplish authentication by using the JNDI API. For example, a client using JNDI can provide authenticating information using the JNDI API to access a server or resource in the server.
properties.put(Context.SECURITY_PRINCIPAL, userName);
properties.put(Context.SECURITY_CREDENTIALS, userPassword);
InitialContext jndiContext = new InitialContext(properties);
Object ref = jndiContext.lookup("TravelAgent");
TravelAgentRemote remote = (TravelAgentRemote) PortableRemoteObject.narrow(ref, TravelAgentRemote.class);
The username and password are associated with the client thread and propagated to the server internally when calls are made to remote EJBs.
EJB security roles are mapped to real-world user groups and users when the bean is deployed. This mapping allows a bean to be portable; every time the bean is deployed in a new system, the roles can be mapped to the users and groups specific to that operational environment.
Assigning Method Permissions
Use the @javax.annotation.security.RolesAllowed annotation to define one or more logical roles that are allowed to access the method.
The @PermitAll annotation specifies that any authenticated user is permitted to invoke the method. @PermitAll is also the default value if no default or explicit security metadata is provided for a method. This means that if you do not use any security annotations on your bean class, every user is granted unlimited access.
<security-role> <description></description> <role-name>AUTHORIZED_MERCHANT</role-name> </security-role>
<method-permission> <role-name>AUTHORIZED_MERCHANT</role-name>
<method> <ejb-name>ProcessPaymentBean</ejb-name><method-name>byCredit</method-name> </method>
The <unchecked> element is equivalent to the @PermitAll annotation.
Wildcard declarations
<method> <ejb-name>ProcessPaymentBean</ejb-name> <method-name>*</method-name> </method>
The asterisk character can only be used by itself.
Specific method declarations use the <method-params> element to pinpoint a method by listing its parameters, which allows you to differentiate between overloaded methods.
Remote/home/local differentiation
The same method name can be used in the remote interface and the local interface. To resolve this ambiguity, add the <method-intf> element to a method declaration as a modifier. Five values are allowed for a <method-intf> element: Remote, Home, LocalHome, Local, and ServiceEndpoint.
Excluded Methods
EJB security metadata has a rarely used feature that allows you to forbid access to one or more methods. Excluded methods are identified with the @DenyAll annotation or with the <exclude-list> element.
The RunAs Security Identity @RunAs
While the @RolesAllowed annotation and <method-permission> elements specify which roles have access to the bean's methods, runAs specifies the role under which the method will run.
the runAs role is used as the enterprise bean's identity when it tries to invoke methods on other beansand this identity isn't necessarily the same as the identity that's currently accessing the bean.
To specify that an enterprise bean will execute under the caller's identity rather than a propagated run-as identity, the <security-identity> role contains a single empty element, <use-caller-identity/>.
Programmatic Security
interface EJBContext {
javax.security.Principal getCallerPrincipal( ); boolean isCallerInRole (String roleName);}
A Principal object represents the individual user that is currently invoking on the EJB.
To make the EJB container's job easier, you must declare all programmatic role access using the @javax.annotation.security.DeclareRoles annotation.
@DeclareRoles ("JUNIOR_TRAVEL_AGENT")
<session> <security-role-ref> <role-name>JUNIOR_TRAVEL_AGENT</role-name> </security-role-ref> </session>
EJB 3.0: Web Services Standards
a web service is a remote application described using the Web Service Description Language (WSDL) and accessed using the Simple Object Access Protocol (SOAP) according to the rules defined by the WS-I Basic Profile 1.1.
XML Schema
An XML Schema is similar in purpose to a Document Type Definition (DTD), which validates the structure of an XML document.
<complexType> element declares a type of element in much the same way that a Java class declares a type of object.
XML Schema automatically supports about two dozen simple data types, called built-in types .
XML Namespaces
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.titan.com/Address"></schema>
The targetNamespace attribute identifies the unique URI of the markup language.
<addr:address xmlns:addr="http://www.titan.com/Address">
Prefixing every element in an XML document with its namespace identifier is a bit tedious, so the XML Namespace allows you to declare a default namespace that applies to all nonprefixed elements. The default namespace is simply an XML Namespace declaration that has no prefix (xmlns="URL").
<reservation xmlns="http://www.titan.com/Reservation">
Default namespaces do not apply to attributes. As a result, any attributes used in an XML document should be prefixed with a namespace identifier. The only exceptions to this rule are attributes defined by the XML language itself.
XML Namespaces are URIs that uniquely identify a namespace but do not actually point at a resource. In other words, you don't normally use the URI of an XML Namespace to look something up. It's usually only an identifier. However, you might want to indicate the location of the XML Schema associated with an XML Namespace so that a parser can upload it and use it in validation. This is accomplished using the schemaLocation attribute
<reservation xmlns="http://www.titan.com/Reservation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance" xsi:schemaLocation="http://www.titan.com/Reservation http://www.titan.com/schemas/reservation.xsd">
The schemaLocation attribute provides a list of values as Namespace-Location value pairs. The first value is the URI of the XML Namespace; the second is the physical location (URL) of the XML Schema.
SOAP is defined by its own XML Schema and relies heavily on the use of XML Namespaces. Every SOAP message that is sent across the wire is an XML document consisting of standard SOAP elements and application data.
SOAP's primary purpose is to establish a standard XML framework for packaging application data that is exchanged between different software platforms.
Web Services Styles
Document/Literal message means that the message body is a single XML Schema instance document, and thus the full message can be validated. For this reason, Document/Literal is becoming the preferred message style of the web services community.
RPC/Literal represents SOAP messages as RPC calls with parameters and return values, each with its own schema type.
EJB 3.0 also supports the RPC/Encoded mode of SOAP messaging. However, the web services industry has moved toward Document/Literal and RPC/Literal, primarily because interoperability between platforms using RPC/Encoded proved to be less than perfect and sometimes downright difficult. Although EJB 3.0 supports RPC/Encoded messaging, it's not a very good option to use in web services.
Exchanging SOAP Messages with HTTP
Another advantage of using HTTP is that SOAP messages can slip through firewalls without any hassles.
The Web Service Description Language (WSDL) is an XML document used to describe a web service.
The root element of a WSDL document is the <definitions> element.
The <portType> and <message> Elements
The <portType> element describes the web services operations (Java methods) that are available. An operation can have input, output, and fault messages. An input message describes the type of SOAP message a client should send to the web service. An output message describes the type of SOAP message a client should expect to get back. A fault message (not shown in the example) describes any SOAP error messages that the web service might send back to the client. A fault message is similar to a Java exception.
JAX-WS supports two styles of web services messaging: request-response and one-way . You know you are dealing with request-response if the <operation> element contains a single <input> element, followed by a single <output> element, and optionally, zero or more <fault> elements.
The one-way message style is implied by the presence of a single <input> element but no <output> or <fault> element.
The request-response style of messaging is the kind you expect in RPC programming; you send a message and get a response. The one-way style tends to be used for asynchronous messaging; you send a message but do not expect a response.
WSDL also supports two other messaging styles: notification (a single <output> and no <input>) and solicitation (a single <output> followed by a single <input>).
message elements describe the parameters and return values.
The <types> Element is used to define any custom types, and it is the first child of the <definitions> element.
The <binding> and <service> Elements
The <binding> element describes the type of encoding used to send and receive messages as well as the protocol on which the SOAP messages are carried. A binding element is always interlaced with protocol-specific elementsusually. a binding is specific to a particular <portType>: its <operation>, <input>, and <output> elements describe the implementation details of the corresponding <portType>.
Universal Description, Discovery, and Integration (UDDI) is a specification that describes a standard for publishing and discovering web services on the Internet. It's essentially a repository with a rigid data structure describing companies and the web services they provide. UDDI is an electronic directory that allows organizations to advertise their business and web services and to locate other organizations and web services.
EJB 3.0 and Web Services
Accessing Web Services with JAX-RPC
by using JAX-RPC, EJBs can access web services across the network hosted on both Java and non-Java platforms, There are three APIs for accessing web services: generated stubs, dynamic proxies, and the Dynamic Invocation Interface (DII). When JAX-RPC is accessed from a Java EE/EJB 3.0 environment, the decision to use a dynamic proxy or a stub is up to the specific container on which you are running. In this case, however, a dynamic proxy will most likely be used because a stub is not portable between Java EE platforms.
A dynamic proxy is very much like the classic Java RMI or CORBA programming model, where the client accesses a remote service via a remote interface implemented by a network stub. The stub translates calls made on the remote interface into network messages that are sent to the remote service.
Generating JAX-RPC Artifacts from WSDL
The primary interface that describes a JAX-RPC web service is called a service endpoint interface. A JAX-RPC-compliant compiler generates the endpoint interface from a WSDL <portType> definition. This interface, when combined with WSDL <binding> and <port> definitions, is used to create the dynamic proxy at deploy time. The organization that hosts the web service provides the WSDL document.
An endpoint interface is a plain Java interface that extends the java.rmi.Remote interface. All methods on the service endpoint interface must throw RemoteException.
JAX-RPC also defines a mapping between complex types defined in the WSDL <types> element and Java bean classes.
When a service is deployed, the proxy, which implements the endpoint interface, is generated from the <binding> and <port> definitions. The JAX-RPC proxy translates the messaging style specified by the <binding> definition into a marshaling algorithm for converting method calls made on the endpoint stub into SOAP request and reply messages.
The proxy is responsible for converting method calls made on the endpoint interface into SOAP messages that are sent to the web service. It's also responsible for converting SOAP response messages sent back to the stub into a return valueor, if it's a SOAP fault message, into an exception thrown by the endpoint method.
The proxy also takes into consideration the <port> definition, which declares the Internet address where the web service is located.
In addition to the service endpoint interface, the JAX-RPC compiler also creates a service interface, which is used to get an instance of the proxy at runtime. The service interface is based on the <service> element of the WSDL document.
Calling a Service from an EJB
The generated JAX-RPC service can be injected directly into a field or setter method of the bean class. It can also be bound to a specific namespace in the JNDI ENC at deployment time. The service can then obtain the proxy.
The <service-ref> Deployment Element
This XML element binds a JAX-RPC service to the JNDI ENC and injects it into the field of our bean class.
<session> <service-ref>
</service-ref> </session>
Defining a Web Service with JAX-RPC
The core component in the EJB model is called an EJB endpoint . An EJB endpoint is a stateless session bean that is exposed as a web service, there is another component interface, called the service endpoint interface which defines the abstract web services contract that the EJB endpoint provides to a web services client.
The WSDL Document
Every EJB endpoint must have a WSDL document that describes the web service.
The Service Endpoint Interface
interface TravelAgentEndpoint extends java.rmi.Remote { java.lang.String makeReservation(int cruiseId, int cabinId, int customerId, double price) throws java.rmi.RemoteException;}
you can start from Java by writing the service endpoint interface by hand, then generate the WSDL and the JAX-RPC mapping file from this interface.
The Stateless Bean Class @Stateless class TravelAgentBean implements TravelAgentEndpoint {}
The Deployment Files: The WSDL file, The JAX-RPC mapping file,
The webservices.xml file
The webservices.xml file is the baling wire that ties the separate deployment files together. It defines the relationships between the stateless session bean, the WSDL file, and the JAX-RPC mapping file.
Using JAX-WS
The @WebService Annotation
The name( ) attribute is the name of the web service and it is used as the name of the portType when mapped to WSDL. This defaults to the short name of the Java class or Java interface to which you are applying it.
The @WebMethod Annotation
If a stateless session bean is annotated with @java.jws.WebService, and it contains no methods that are annotated with @WebMethod , then all methods are made available to the web service. Otherwise, only those methods that are annotated with @WebMethod will be made available
The operationName( ) attribute is used to define the WSDL operation that the annotated method implements. If it is not specified, the literal Java method name is used.
The @SOAPBinding Annotation
The @WebParam Annotation
If the style is RPC/Literal, the name( ) attribute sets the wsdl:part name. Otherwise, it sets the XML local name of the element within the schema document that corresponds to the annotated parameter. If it is not specified, the default value is computed in the form of argN, where N is the 0-based position of the parameter in the method signature.
@WebMethod(operationName = "CheckStatus")
int checkStatus( @WebParam(name = "ReservationID") String reservationId, @WebParam(name = "CustomerID", mode = WebParam.Mode.OUT) javax.xml.ws.Holder<Integer> customerId)
customerId.value = getCustomerId(reservationId);
The mode( ) attribute is used to indicate whether the parameter is to be used for input, output, or both. Due to Java semantics, if a parameter is used for output, it must be wrapped using a special holder type.
The @WebResult Annotation
If the name( ) attribute is not specified, and the style is Document/Literal bare, then its value will be the WSDL operation name concatenated with "Response". For all other styles, the default is "return".
The @OneWay Annotation
The @OneWay annotation is used to declare that the corresponding web services operation will return an empty message. This allows the server and the client to optimize the operation by performing the method invocation asynchronously. Whether the method is actually executed asynchronously is determined by the Java EE implementation. The resulting WSDL for a one-way operation will not have an <output> tag.
Separating the Web Services Contract
Up to this point, we have been defining everything within the EJB implementation class. An alternative approach is to use the endpointInterface( ) attribute of the @WebService annotation. The web services contract can then be maintained in an external Java interface. With this methodology, the only required annotation on the endpoint interface is @WebService. All other annotations are optional. Unlike the previous approach of keeping everything within the EJB implementation, all methods in the interface are exposed in the web service.
@WebService interface TravelAgentEndpoint{}
@WebService(endpointInterface = "com.titan.webservice.TravelAgentEndpoint") class TravelAgentBean implements TravelAgentEndpoint {}
The Service Class
JAX-WS contains a service class that the JAX-WS client uses to communicate with a web service. The service class must extend javax.xml.ws.Service and provide a method to retrieve the service endpoint interface. It should also use the @javax.xml.ws.WebServiceClient annotation to define the name, namespace, and WSDL location of the service. The @javax.xml.ws.WebEndpoint annotation is necessary to resolve for which WSDL <port> to return a proxy.
@WebServiceClient(name="ProcessorService", targetNamespace="http://charge-it.com/Processor" wsdlLocation="http://charge-it.com/Processor?wsdl") class ProcessorService extends javax.xml.ws.Service {
ProcessorService( ) { super(new URL("http://charge-it.com/Processor?wsdl"),new QName("http://charge-it.com/Processor", "ProcessorService")); }
ProcessorService(String wsdlLocation, QName serviceName) { super(wsdlLocation, serviceName); }
@WebEndpoint(name = "ProcessorPort") Processor getProcessorPort( ) { return (Processor)super.getPort(new QName("http://charge-it.com/Processor", "ProcessorPort"),Processor.class); }}
The Service Endpoint Interface
Client can also use the same Service Endpoint Interface.
The @WebServiceRef Annotation
A JAX-WS client can use the @WebServiceRef annotation to reference either a service interface or a service endpoint interface directly.
@WebServiceRef(ProcessorService.class) Processor processor;
The annotation will cause a dynamic proxy that implements the Processor interface to be injected into the processor field.