1/86

2/9/2008

SCBCD FOR J2EE 1.3 (CX-310-090) - CONTENTS INTRODUCTION..........................................................................................................................................3 SOA and Web Services............................................................................................................................3 EJB Ecosystem........................................................................................................................................3 J2EE Technologies..................................................................................................................................4 Java RMI-IIOP.......................................................................................................................................5 JNDI........................................................................................................................................................6 Integrating RMI-IIOP and JNDI............................................................................................................8 EJB Fundamentals..................................................................................................................................8 Middleware.............................................................................................................................................8 EJB Object..............................................................................................................................................9 Remote Interface.....................................................................................................................................9 Home Interface and Object.....................................................................................................................9 Local Interface......................................................................................................................................10 Deployement Descriptor.......................................................................................................................11 SESSION BEANS.........................................................................................................................................11 Lifecycle................................................................................................................................................11 Stateful Session Beans..........................................................................................................................13 Stateless Session Beans.........................................................................................................................13 Comparing Stateful and Stateless Session Beans.................................................................................13 Remote Interface:..................................................................................................................................14 Local Interface:....................................................................................................................................14 Home Interface:....................................................................................................................................15 Local Home Interface ..........................................................................................................................16 Session Bean Class...............................................................................................................................16 EJB Context..........................................................................................................................................17 Deployement Descriptor.......................................................................................................................17 EJB Jar file...........................................................................................................................................18 Client code............................................................................................................................................19 To Remember….....................................................................................................................................20 WEBSERVICES USING STATELESS SESSION BEANS......................................................................20 WSDL....................................................................................................................................................21 ENTITY BEANS...........................................................................................................................................24 Load and Store......................................................................................................................................25 Types ....................................................................................................................................................25 Create and Remove...............................................................................................................................25 Entity Context ......................................................................................................................................26 getPrimaryKey() : ................................................................................................................................26 Finder methods:....................................................................................................................................26 BEAN MANAGED PERSISTENT (BMP) ENTITY BEANS..................................................................27 BMP ENTITY BEAN WITH LOCAL INTERFACE.......................................................................................................28 Local interface......................................................................................................................................28 Local Home Interface...........................................................................................................................29 Primary Key class.................................................................................................................................29 Custom Exception (Application Level).................................................................................................30 Entity Bean Class..................................................................................................................................30 Deployment Descriptor.........................................................................................................................36 Client Code...........................................................................................................................................38 CONTAINER MANAGED PERSISTENT (CMP) ENTITY BEANS.....................................................41

© 2006, Watsh Rajneesh. All Rights Reserved.

2/86

2/9/2008

Abstract Persistence Schema................................................................................................................42 EJB QL .................................................................................................................................................42 ejbSelect() – only in CMP.....................................................................................................................42 Bean Class Code...................................................................................................................................44 Deployment Descriptor.........................................................................................................................47 MESSAGE DRIVEN BEAN........................................................................................................................48 Java Messaging Service (JMS).............................................................................................................49 Messaging Domains..............................................................................................................................49 JMS Programming Model.....................................................................................................................50 Bean class.............................................................................................................................................52 Client (Message Producer)...................................................................................................................53 Deployment Descriptor.........................................................................................................................55 EJB ENVIRONMENT & BEST PRACTICES..........................................................................................60 EJB References.....................................................................................................................................61 Resource Factories...............................................................................................................................62 Environment Properties........................................................................................................................63 EJB Object Handles..............................................................................................................................63 Home Handles......................................................................................................................................64 TRANSACTIONS.........................................................................................................................................66 Transaction Jargons.............................................................................................................................67 Transactional Models...........................................................................................................................67 Transaction Attributes...........................................................................................................................69 Java Transaction API (JTA)..................................................................................................................72 Transaction Isolation............................................................................................................................74 Durability and Two phase commit protocol..........................................................................................75 SECURITY....................................................................................................................................................76 EJB TIMER SERVICE................................................................................................................................77 RELATIONSHIP BETWEEN ENTITY BEANS......................................................................................77 Cardinality............................................................................................................................................77 Directionality........................................................................................................................................83 Aggregation vs Composition and Cascading Deletes...........................................................................84 EJB INTEGRATION (JCA)........................................................................................................................85 EJB PERFORMANCE TUNING...............................................................................................................85 CLUSTERING..............................................................................................................................................86 SAMPLE APPLICATION...........................................................................................................................86

Revision # 0.1

Date 16th May, 2006

Changes Initial Version.

Disclaimer: This document is my notes taken from the book Mastering EJB 3rd Edn. by Ed Roman et al and Head First EJB by Kathy Sierra and Bert Bates. This document covers more than the syllabus for the SCBDC exam and is well suited for revising the concepts of EJB 2.0 and 2.1.

© 2006, Watsh Rajneesh. All Rights Reserved.

3/86

2/9/2008

Introduction
EJB is about rapid application development for the server side; you can quickly and easily construct server-side components in Java by leveraging a prewritten distributed infrastructure provided by the industry. EJB is designed to support application portability and reusability across any vendor’s enterprise middleware services.

SOA and Web Services
A service-oriented architecture (SOA) thus is a paradigm focusing on development of services rather than piecemeal components such that these services provide a higher level of abstraction from a functional standpoint. Of course, there are more properties to SOA than mere coarsegranularity. One such characteristic property of SOA is that they are autonomous in nature. These independent entities can interact with others in spite of differences in the way they have been implemented or the platform they have been deployed on. The notion of putting together (integrating) such autonomous and loosely coupled services to address the changing business needs has a huge value proposition and it is well on its way to realization with the emergence of various choreography, orchestration and collaboration technologies such as WS-BPEL, EbXML BPSS, and WS Choreography. SOA is a paradigm. There are many possible ways of building software so that it implements salient features of SOA, mainly coarse granularity and loose coupling. One such way is Web services. Simple Object Access Protocol (SOAP) is an XML-based application-level protocol intended for exchanging information in a distributed network. SOAP supports both the models of distributed computing: RPC as well as document style messaging. RPC style SOAP allows remote invocation of operations. Parameters and return in/out values of these operations are serialized in XML. Whereas, in document-style SOAP because an operation’s input and output are XML, serialization of parameters and return value to XML is not needed. Web Service Description Language (WSDL) is an XML-based metadata standard that is used to describe the service interface—in terms of the operations it supports, the parameters that the operations accept, and their return values in case of SOAP RPC, the XML schema that the input and output messages to the operations in case of document-style SOAP—as well as service binding information— in terms of the communication protocols, ports, service URL, and so on. SOA is not a replacement for component architecture; rather it neatly complements the component architecture. While component architectures enhance reusability at a finer grain level, SOA can enhance reusability at a coarser grained level. Hence, from an implementation standpoint, a given service might very well be developed using well-defined component frameworks such as EJB. The latest EJB standard, therefore, has in-built support for Web Services, the most popular stack for building SOA.

EJB Ecosystem
Bean Provider (Internal department providing EJBs to other departments Developers writing the EJBs.

© 2006, Watsh Rajneesh. All Rights Reserved.

4/86

2/9/2008

or third party vendor). Application Assembler (System integrators, a consulting firm or inhouse programmer.)

   

Assemble the beans to make an application. Supply a UI (standalone or web based) or webservice. Write new EJB to solve application specific problem. Code that conncets the EJBs provided by bean providers with the application code.

EJB Deployer (a staff person, a vendor or consultant).

System Administrator

Server Provider (BEA, IBM, JBoss(now Redhat)). Tools Vendor (BEA Weblogic Provide IDEs to build/debug EJBs. Workshop, IBM Websphere Application Studio, Eclipse, Netbeans, IntelliJ IDEA). Bean provider, application assembler and deployer could be the same person for small companies.

Securing deployement within h/w or s/w firewall. Integrating with enterprise security and policy repositories, which oftentimes is an LDAP server  Choosing h/w to host the application.  Providing redundant h/w for clustering.  Performance tuning the system (by modifying the deployement descriptors).  Oversee the stability of operational system.  Upkeep and monitoring of deployed system making use of management tools that the EJB server provides (JMX console of JBoss) or Weblogic AS provides SNMP manageability. Provides EJB container (Application Server).  

J2EE Technologies
EJB 2.1 JAX-RPC RMI-IIOP JNDI JTA & JTS JMS Defines how server side components are written and provides a standard contract between components and application server (container). Support for developing Webservices. Defines two webservices endpoint models: one based on servlet and other based on stateless session EJB. Extension of RMI for CORBA integration. Used to access naming and directory systems such as Microsoft Exchange or Lotus Notes. Allow for components to be bolstered with transaction support. Allows for J2EE deployement to communicate using messaging within and outside the J2EE system. You can connect to existing MOM (message oriented middleware – IBM MQSeries or MS MQ). Messaging is an alternative to RMI-IIOP. Enable J2EE systems to access existing EIS such as mainframe systems running high-end transactions (like IBM CICS, BEA TUXEDO), ERP systems or prorietary systems. ISVs such as SAP, Siebel, PeopleSoft (now Oracle) who want their software to be accessible from within J2EE application servers can write standard J2EE connectors which will act similar to JDBC service provider jars. API for parsing XML documents. Is implementation neutral interface to XMP parsing technologies such as DOM and SAX. So you can plugin a DOM/SAX parser implementation like Xerces for Java and use Xerces from JAXP APIs.

JCA

JAXP

© 2006, Watsh Rajneesh. All Rights Reserved.

5/86

2/9/2008

JAAS

Standard API for performing security related operations.

Java RMI-IIOP
RMI-IIOP is special version of RMI that is compliant with CORBA and uses both java.rmi and javax.rmi. RMI-IIOP lacks some features present in RMI like:  Distributed garbage collection.  Object activation.  Downloadable class files. RMI-IIOP supports both pass-by-reference and pass-by-value models. Following are the steps to build an RMI-IIOP application: 1. When using RMI-IIOP you must build a custom interface called Remote Interface which extends java.rmi.Remote.
import java.rmi.Remote; import java.rmi.RemoteException; /** * The remote interface for the remote object. Clients use this * remote interface to perform any operations on the remote object. */ public interface IPKGenerator extends Remote { public long generate() throws RemoteException; }

2.

To make your object available as a remote object and allow remote hosts to invoke its methods, your remote class must either a. extend the javax.rmi.PortableRemoteObject class or b. in case your class already extends some other class then you can manually export your object so that it is available to be invoked on by remote hosts by calling javax.rmi.PortalRemoteObject.exportObject().
import java.rmi.RemoteException; import javax.rmi.PortableRemoteObject; /** * The remote object which generates primary keys */ public class PKGenerator extends PortableRemoteObject implements IPKGenerator { /* * Our remote object’s constructor */ public PKGenerator() throws Exception, RemoteException { /* * Since we extend PortableRemoteObject, the super * class will export our remote object here. */ super(); } /* * Generates a unique primary key */ public synchronized long generate() throws RemoteException { return i++; } private static long i = System.currentTimeMillis();

}

The remote object can be made unavailable for remote method invocation by calling javax.rmi.PortableRemoteObject.unexportObject().

© 2006, Watsh Rajneesh. All Rights Reserved.

6/86

2/9/2008

2. rmic compiler can be used to generate the stub and skeleton which are proxy’s responsible for
3. 4. delegating the calls made to remote methods to their implementations. Passing parameters by value for object type requires the object type to be serializable. Passing object type parameters by reference is achieved when parameter object is itself a remote object. So when the client makes a remote method call on the server and passes a remote object reference of a remote object living on the client machine then the stub to that remote object reference is serialized (and not the whole object). So the server can connect to the remote object living on client machine and invoke methods on that. Java RMI-IIOP thus simulates the pass-byreference by passing serializable stub, rather than serializing the original object. So, by making your parameters remote objects, you can effectively avoid the network lag in passing large objects. Note: the Java RMI-IIOP stubs are serializable always. In summary, following are the rules for passing objects using Java RMI-IIOP: All Java primitives are passed by value when calling methods remotely. If you want to pass an object by value, it must implement java.lang.Serializable interface. Anything referenced from within the object must also be serializable. 3. If you want to pass an object by reference, it must be a remote object, and it must implement java.rmi.Remote interface. A stub for the remote object is serialized and passed to the remote host. A way to publish the server and have client locate the server is called bootstrapping and is achieved by JNDI. 1. 2.

JNDI
JNDI provides standard inteface for locating users, machines, networks, objects and services by name. Example, locating a printer on the network by name, locating java object or locating a datasource to connect to a database. In J2EE the uses of JNDI are: 1. acquire a reference to the Java Transaction API (JTA) UserTransaction interface 2. connect to resource factories such as, JDBC drivers or JMS drivers. 3. for beans to lookup other beans. Naming service:  Associates names with objects (binding names to objects).  Provides a facility to find an object by name (resolving a name to an object reference). Example, filesystem (file name to file handle), DNS (machine name to IP address). A directory object is a special type of object stored with the naming service which can be used to store attributes. Eg. You can use a directory object to represent a user storing information about user, like user loginid, password, email, phone etc as its attributes. So your application can lookup the user credentials stored in the directory object of the naming service to authenticate the user. A directory service is a naming service enhanced to provide directory object operations for manipulating attributes. Eg, (MS Active Directory Service, Netscape Directory Server). Directory is a system of directory objects that are all connected in a hierarchical tree structure with a root representing your company as shown below:

© 2006, Watsh Rajneesh. All Rights Reserved.

7/86

2/9/2008

Most directories are implemented by a database behind the scene to store the hierarchical directory objects. There are several directory protocols for accessing a directory service eg. LDAP (Light weight directory access protocol) or Novell’s Network Directory System (NDS) or Network Information System (NIS). IBM’s Lotus Notes and Microsoft Active Directory are both LDAP based. But not all directory services are LDAP based. JNDI is a bridge over naming and directory services providing common interface to disparate directories. Similar to JDBC, JNDI has two halves: 1. API – allows clients to code to a single unified interface 2. SPI – allows naming and directory service vendors to fit their particular proprietary protocols into the system. Like the database vendors provide JDBC drivers, directory service vendors provide JNDI service providers to access their specific directories. The providers are aware of specific directory protocols and they plugin to the JNDI SPI. LDAP service provider would know how to map JNDI client API to an LDAP operation. Service providers exist for LDAP, NIS, NDS, SLP, CORBA NS, File System, RMI-IIOP tnameserv, and many more. Application servers also ship JNDI naming service implementation.

    

Binding: associating name with an object. Context: set of zero or more bindings. Subcontext: is a full fledged context in its own right and can contain more name bindings. Naming system: is a connected set of contexts that use the same name syntax. (eg branch of LDAP tree or a folder tree in file system). Namespace: set of names contained within a naming system.

© 2006, Watsh Rajneesh. All Rights Reserved.

8/86

2/9/2008

Composite name: name that spans multiple naming systems. http://java.sun.com/products/ejb/index.jsp is composed of namespaces: o http: url scheme id namespace. o java.sun.com – uses DNS to resolve to ip address o products/ejb/index.jsp: are from filesystem namespace on webserver. Initial Context: is starting point of exploring a namespace. (root node of the naming system).

Eg.

To acquire an initial context in JNDI, we use an initial context factory (implemented by JNDI service provider) which returns the initial context for the naming system. To get an initial context for a certain naming system you need to provide the following information about the naming system: o IP address of the naming system o Port number at which the naming service is listening o Starting location within the JNDI tree o User name and passwd for authenticating to the naming service (if applicable). Note: Naming graphs needed not be trees. They may have more than one root. Subcontexts can be bound in more than one context, so a single subcontext may be known under more than one name.

Integrating RMI-IIOP and JNDI
1. 2. Binding RMI-IIOP Server to JNDI Looking up an RMI-IIOP server with JNDI

EJB Fundamentals
Session Beans Entity Beans Message driven Beans Model business processes. Model business data. Can be called only implicitly by sending messages to those beans. Eg. Stock trade messages, credit card authorization messages, workflow messages.

Middleware
When distributed system grows larger, we need to employ middleware services for transaction, security, persistence, etc. Explicit Middleware: involves purchasing a middleware off the shelf and writing code that calls the middleware’s API. More like Bean managed transaction/persistence/security. Business logic gets intwined with the logic to call these middleware APIs. Example of such systems are: traditional CICS or TUXEDO based mainframe systems, CORBA, DCOM or RMI. Implicit/Declarative Middleware: New component based technologies like EJB, .NET and CORBA Component Model enable you to harness the complex middleware in enterprise applications without writing to the middleware APIs. More like Container Managed transaction/persistence/security. You just do the following: 1. Write distributed object business logic only. 2. Declare middleware services that your distributed object needs in separate descriptor files. 3. The application server will generate the request interceptor from the configuration obtained from the descriptor files. 4. Request interceptor will intercept requests from client, perform middleware services that your distributed object needs and then delegates the call to the distributed object.

© 2006, Watsh Rajneesh. All Rights Reserved.

9/86

2/9/2008

EJB Object
EJB is not full fledged remote object. Clients never invoke the business method directly on actual bean instance. Rather, the EJB container intercepts the request, performs the implicit middleware and delegates to the bean instance. EJB container handles networking for you by wrapping your bean in a network enabled object. Middleware services at the point of interception include: 1. Transaction service 2. Security service 3. Resource management: for resources like threads, database connections etc. 4. Lifecycle management of the beans: pooling the beans, activating/passivating etc. 5. Persistence service 6. Handle concurrent requests – either by allowing serial access to the bean instance or allowing other bean instances in the pool to service the request. Thus, EJB container acts as a layer of indirection between client and the bean by providing a network aware wrapper object called EJB Object. EJB Object is the request interceptor. They have container specific code inside them (each container handles middleware differently). EJB Object class file is generated automatically by the container.
public interface javax.ejb.EJBObject extends java.rmi.Remote { public javax.ejb.EJBHome getEJBHome() throws java.rmi.RemoteException; public java.lang.Object getPrimaryKey() throws java.rmi.RemoteException; public void remove() throws java.rmi.RemoteException, javax.ejb.RemoveException; public javax.ejb.Handle getHandle() throws java.rmi.RemoteException; public boolean isIdentical(javax.ejb.EJBObject) throws java.rmi.RemoteException; }

Remote Interface
For the container to know what business methods have to made remote you will need to provide a Remote interface which mentions all business methods that bean class exposes. Your remote interface extends the javax.ejb.EJBObject interface mentioning all business methods of your bean. When a client invokes any of these business methods, the EJBObject delegates the method to its corresponding implementation, which resides in the bean itself. So the container provided EJBObject concrete implementation implements the Remote interface we create and provides an implementation for the methods in the javax.ejb.EJBObject interface plus implementation of the business methods which simply call the business method implementation in your bean class. java.rmi.Remote extended by javax.ejb.EJBObject extended by <YourBean>Remote Container generated concrete class might look like this: class <YourBean>EJBObjectImpl implements <YourBean>Remote { // override all methods in javax.ejb.EJBObject // override all methods in <YourBean>Remote // provide middleware services based on confign. in deployement descriptor – implicit middleware // delegate the call to <YourBean> methods. }

Home Interface and Object
To acquire a reference to an EJB object, your client code asks for an EJB object from an EJB object factory. This factory is resposible for instatiating and destroying EJB objects. This factory is the Home object.

© 2006, Watsh Rajneesh. All Rights Reserved.

10/86

2/9/2008

Home object is generated by the container and implements the Home interface where you provide information to the container about how your bean instance has to be initialized while instantiating. Even instantiation of the bean will be done via the EJB object instance.
public interface javax.ejb.EJBHome extends java.rmi.Remote { public EJBMetaData getEJBMetaData() throws java.rmi.RemoteException; public javax.ejb.HomeHandle getHomeHandle() throws java.rmi.RemoteException; public void remove(javax.ejb.Handle handle) throws java.rmi.RemoteException, javax.ejb.RemoveException; public void remove(Object primaryKey) throws java.rmi.RemoteException, javax.ejb.RemoveException; }

java.rmi.Remote extended by javax.ejb.EJBHome extended by <Your Bean>Home Container generated Home object concrete implementation will be: class <YourBean>HomeImpl implements <Your Bean>Home { // override methods in javax.ejb.EJBHome interface // override methods in <Your Bean>Home interface // delegating calls for create/find/remove to corresponding EJB object // EJB object in turn delegates to bean instance // if create – invokes the bean constructor or picks one bean from the instance pool // if find – invokes the corresponding entity bean’s finder method // if remove – reinits the state of bean and returns it to instance pool } Note: Most containers will have a 1:N relationship between home objects and bean instances. This means that all clients use the same home object instance to create EJB objects. So a home object will be implemented by container to be thread safe code as it has to service multiple clients. Your beans will always be single threaded (ie only one thread at a time will execute methods of a certain bean instance). Relationship between EJB objects and bean instances may be 1:N (as home objects) or M:N. In the former case, the EJB object will be single and so will be thread safe. In the later case, there will be as many EJB objects as there are active client connections (so EJB objects will be single threaded).

Local Interface
Local objects implement local interfaces. Avoids the networking overhead.
public interface javax.ejb.EJBLocalObject { public javax.ejb.EJBLocalHome getEJBLocalHome() throws javax.ejb.EJBException; public Object getPrimaryKey() throws javax.ejb.EJBException; public boolean isIdentical(javax.ejb.EJBLocalObject) throws javax.ejb.EJBException; public void remove() throws javax.ejb.RemoveException, javax.ejb.EJBException; } public interface javax.ejb.EJBLocalHome { public void remove(java.lang.Object) throws javax.ejb.RemoveException, javax.ejb.EJBException; }

javax.ejb.EJBLocalObject extended by <Your Bean>Local and

© 2006, Watsh Rajneesh. All Rights Reserved.

11/86

2/9/2008

javax.ejb.EJBLocalHome extended by <Your Bean>LocalHome Note: Local interface always marshall parameters by reference.

Deployement Descriptor
This is the key to implicit middleware. It is used to inform the container about your middleware needs, you as a bean provider must declare your components’ middleware service requirements in this file. Bean Management and How container should manage your beans. lifecycle requirements o name of bean class o type of bean (Session, Entity or MDB) o home interface that generates the beans o local or remote Persistence requirements Whether bean or container managed persistence. (Entity beans only) Transaction requirements Requirements for running in transactions Transaction must start whenever anyone calls a bean (Required New) Transaction may start whenever there is no running transaction (Required) etc Security requirements Access control entries Who is allowed to use which beans Who is allowed to use each method on a particular bean Vendor Specific files can be used to configure load balancing, clustering, monitoring, pool sizes etc. EJB-jar file = bean classes + home interfaces + remote interfaces + deployement descriptor.

Session Beans
Session beans are business process objects that implement business logic and workflows. Eg. Price quoting, order entry, video compression, banking transactions, stock tradesm database operations, complex calculations etc.

Lifecycle
Lifetime is equivalent of a client session. Session bean instances are not shared between clients. EJB container may destroy the session bean if client times out. Session beans are non persistent (not saved to database). Stateless bean lifecycle: 1. Bean instance does not exist 2. container decides it wants to instantiate a new bean (depends on container’s policy for pooling beans) 3. container instantiates your bean : container calls class.newInstance(“HelloBean.class”) on your session bean class. 4. container calls setSessionContext() : associating a bean with context which enables it to make callbacks to container. 5. container calls ejbCreate() : initializes your bean. 6. container can call business methods on your bean : container can dynamically reassign beans to client requests at the per-method level. 7. container calls ejbRemove().

© 2006, Watsh Rajneesh. All Rights Reserved.

12/86

2/9/2008

Lifecycle of stateful session bean is similar to that of stateless session bean, except: 1. there is no pool of equivalent instances because each instance contains state. 2. there are transitions for passivating and activating conversational state.

© 2006, Watsh Rajneesh. All Rights Reserved.

13/86

2/9/2008

Stateful Session Beans
Designed to service business processes that span multiple method requests or transactions. They retain the state on behalf of an individual client. Eg. E-commerce web store and shopping cart. To limit the number of stateful session bean instances in memory, the container can swap out a stateful bean, saving its conversational state to a hard disk (passivation). At passivation time the container uses object serialization to save state of bean (javax.ejb.EnterpriseBean interface extends java.io.Serializable interface – so every enterprise bean implements this interface). When the original client invokes a method, the passivated conversational state is swapped in to a bean (activation) which then resumes conversation with the original client. The bean that receives the activated state may not be the original bean instance that was passivated. Containers may choose to passivate a bean that has been used least recently (LRU). Passivation can occur anytime if the bean is not involved in a method call or is not a part of a transaction. Beans are activated on-demand (as client request comes in). Thus, using passivation/activation, the EJB container provides effect of instance pooling stateful session beans. ejbPassivate() – relinquish held resources like database connections, open sockets, open files. ejbActivate() – restore the open resources it released during ejbPassivate(). Note: in most cases you leave these methods empty. But you may implement them if you do have transient resources which you donot want to save like socket connections, open files, database connections etc which you have stored in private member instance variables but that does not make sense to serialize everytime with the object state.

Stateless Session Beans
Designed to service business processes that span a single method call. The client must pass all client data that the bean needs as parameters to business logic methods. Eg. High-performance engine that solves complex mathematical operations in a given input, such as compression of audio/video data (client passing the buffer of uncompressed data and a compression factor) or a credit card verification component (where client passes the card number, expiry date, holder’s name and amount to debit as input parameters). Note: 1. Stateless session beans can contain state that is not specific to any one client, such as database connection factory that all clients would use. Any stateless bean can service any client request because they are all exactly same. So stateless session beans can be pooled and reused. Passivation/activation are not required as there isnt any state to save. Stateless session beans can also be webservice endpoints.

2.
3.

Comparing Stateful and Stateless Session Beans
Method setSessionContext() ejbCreate() Stateful implementation Stateless Implementation Store the context away in a member variable so that context can be queried later. Perform any initialization your bean needs Perform any initialization. such as setting member variables to the argument values passed in. You can only define an empty You can define several overloaded ejbCreate() method (with no ejbCreate() methods, each taking a different parameters). If it had params and argument. Atleast one ejbCreate() method the bean initialized itself to those MUST be provided. params the bean would never remember what it initialized itself to upon subsequent calls, since its stateless!

© 2006, Watsh Rajneesh. All Rights Reserved.

14/86

2/9/2008

ejbPassivate() ejbActivate() ejbRemove()

Release resource which are transient or you Not Applicable. don’t want serialized on passivation. Acquire resources release while passivation. Not Applicable. Prepare for destruction by releasing resources if any.

Remote Interface:
/** * This is the HelloBean remote interface. * * This interface is what clients operate on when * they interact with EJB objects. The container * vendor will implement this interface; the * implemented object is the EJB object, which * delegates invocations to the actual bean. */ public interface Hello extends javax.ejb.EJBObject { /** * The one method - hello - returns a greeting to the client. */ public String hello() throws java.rmi.RemoteException; }

Local Interface:
/** * This is the HelloBean local interface. * * This interface is what local clients operate * on when they interact with EJB local objects.

© 2006, Watsh Rajneesh. All Rights Reserved.

15/86

2/9/2008

* The container vendor will implement this * interface; the implemented object is the * EJB local object, which delegates invocations * to the actual bean. */ public interface HelloLocal extends javax.ejb.EJBLocalObject { /** * The one method - hello - returns a greeting to the client. */ public String hello(); }

Home Interface:
/** * This is the home interface for HelloBean. This interface * is implemented by the EJB Server’s tools - the * implemented object is called the Home Object, and serves * as a factory for EJB Objects. * * One create() method is in this Home Interface, which * corresponds to the ejbCreate() method in HelloBean. */ public interface HelloHome extends javax.ejb.EJBHome { /* * This method creates the EJB Object. * * @return The newly created EJB Object. */ Hello create() throws java.rmi.RemoteException, javax.ejb.CreateException; }

create() is the factory method that clients use to get a reference to the EJB Object and it initializes the bean. Since a remove() method is already there in the EJBHome interface so we donot need to provide that in our home interface. Note: create() and remove() are for creation and destruction of an EJB object. The bean instance may not be destroyed on a remove() or may not be created on create() (rather be dequed from the pool on create() and returned to the instance pool on remove). Types of Exceptions thrown by bean: A remote exception indicates a special error condition – a network failure, machine failure etc. 1. System level exception – critical failure eg database malfunction 2. Application level exception – routine exception eg bad parameter passed to remote method, warning of an insufficient bank account balance to make withdrawl etc. EJB container can intercept exceptions and decide whether a client should be shown the exception. If a bean fails it may be possible to salvage the client’s invocation and redirect to another bean – transparent fail over. 1. A system level exception is thus intercepted by container and may not be shown to the client. 2. If the failure is fatal then the container can alert the system admin via a monitoring system like sending an snmp trap/ jmx event which system admin can observe in his monitoring application. 3. EJB object is also responsible for catching all unchecked exceptions that your bean may throw (such as NullPointerException) which are typically not handled in the bean code. EJB object then may throw such an unchecked exception back to the client as a remote exception. In summary, 1. Application level exceptions are always thrown back to client. This includes any exception that bean defines and javax.ejb.CreateException or javax.ejb.FindException. 2. For system level exceptions, EJB container can handle the exception and

© 2006, Watsh Rajneesh. All Rights Reserved.

16/86

2/9/2008

3.
4.

a. Inform the system admin with an alert b. Send an email to third party c. Throw exception back to client. Your bean can throw a system level exception as either a java.rmi.RemoteException or an unchecked RuntimeException. If container throws this exception back to client then its always thrown as a RemoteException or a subclass of it. Exceptions also impact transactions.

Local Home Interface
/** * This is the local home interface for HelloBean. * This interface is implemented by the EJB Server’s * tools - the implemented object is called the * local home object, and serves as a factory for * EJB local objects. */ public interface HelloLocalHome extends javax.ejb.EJBLocalHome { /* * This method creates the EJB Object. * * @return The newly created EJB Object. */ HelloLocal create() throws javax.ejb.CreateException; }

Session Bean Class
/** * Demonstration stateless session bean. */ public class HelloBean implements javax.ejb.SessionBean { private SessionContext ctx; // // EJB-required methods // public void ejbCreate() { System.out.println(“ejbCreate()”); } public void ejbRemove() { System.out.println(“ejbRemove()”); } public void ejbActivate() { System.out.println(“ejbActivate()”); } public void ejbPassivate() { System.out.println(“ejbPassivate()”); } public void setSessionContext(javax.ejb.SessionContext ctx) { this.ctx = ctx; } // // Business methods // public String hello() { System.out.println(“hello()”); return “Hello, World!”; }

}

© 2006, Watsh Rajneesh. All Rights Reserved.

17/86

2/9/2008

EJB Context
Inside the bean you may want to access the security credential of the user currently calling your bean’s method. Container holds all this information in an EJB Context object. So a context represents a way for a bean to perform callbacks to the container. EJB Context encapsulates the bean’s domain. The container is responsible for changing the context to reflect any status change, such as bean being involved in a new transaction. Context object state will dynamically change over time. The container associates your bean with a context by calling your setSessionContext() (or setEntityContext(), setMessageDrivenContext()). When you define each of these methods, you should store the context away in a member variable so that the context can be queried later.
public interface javax.ejb.EJBContext { /* * Call these from within your bean to access * your own home object or local home object. * * You can use them to create, destroy, or * find EJB objects and EJB local objects * of your own bean class type. */ public javax.ejb.EJBHome getEJBHome(); public javax.ejb.EJBLocalHome getEJBLocalHome(); /* * These are transaction methods */ public boolean getRollbackOnly(); public void setRollbackOnly(); public javax.transaction.UserTransaction getUserTransaction(); /* * These are security methods */ public boolean isCallerInRole(java.lang.String); public java.security.Principal getCallerPrincipal();

}

public interface javax.ejb.SessionContext extends javax.ejb.EJBContext { public javax.ejb.EJBLocalObject getEJBLocalObject(); public javax.ejb.EJBObject getEJBObject(); }

Deployement Descriptor
ejb-jar.xml – standard ejb deployement descriptor.
<?xml version = "1.0" encoding = "UTF-8"?> <!-Copyright 2004 Sun Microsystems, Inc. All rights reserved. SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. --> <ejb-jar xmlns = "http://java.sun.com/xml/ns/j2ee" version = "2.1" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"> <display-name>HelloWorld</display-name> <enterprise-beans> <session> <display-name>HelloWorld</display-name> <ejb-name>HelloWorld</ejb-name> <home>examples.HelloHome</home> <remote>examples.Hello</remote> <ejb-class>examples.HelloBean</ejb-class> <session-type>Stateless</session-type>

© 2006, Watsh Rajneesh. All Rights Reserved.

18/86

2/9/2008

<transaction-type>Container</transaction-type> <security-identity> <use-caller-identity/> </security-identity> </session> </enterprise-beans> </ejb-jar>

sun-ejb-jar.xml – vendor specific file. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.0 EJB 2.1//EN " "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_2_1-0.dtd"> <sun-ejb-jar> <enterprise-beans> <unique-id>1</unique-id> <ejb> <ejb-name>HelloWorld</ejb-name> <jndi-name>HelloHome</jndi-name> </ejb> </enterprise-beans> </sun-ejb-jar>

EJB Jar file
jar cf HelloWorld.jar * The contents of jar file will look like this:

* examples is the package. You can generate the EJB Client jar file from the deploytool which includes classes that must be deployed for any clients of a particular EJB jar file. Start the Sun AS 8.1 PE as follows: asadmin –start-domain domain1 Then browse to the url: http://localhost:4848 and login to the admin console. From there you can deploy the EJB jar file in EJB Modules section.

© 2006, Watsh Rajneesh. All Rights Reserved.

19/86

2/9/2008

Client code
import javax.naming.Context; import javax.naming.InitialContext; import java.util.Properties; /** * This class is an example of client code that invokes * methods on a simple stateless session bean. */ public class HelloClient { public static void main(String[] args) throws Exception { /* * Setup properties for JNDI initialization. * * These properties will be read-in from * the command-line. */ Properties props = System.getProperties(); /* * Obtain the JNDI initial context. * * The initial context is a starting point for * connecting to a JNDI tree. We choose our JNDI * driver, the network location of the server, etc. * by passing in the environment properties. */ Context ctx = new InitialContext(props); /* * Get a reference to the home object - the * factory for Hello EJB Objects */ Object obj = ctx.lookup(“HelloHome”); /* * Home objects are RMI-IIOP objects, and so * they must be cast into RMI-IIOP objects * using a special RMI-IIOP cast. * */ HelloHome home = (HelloHome) javax.rmi.PortableRemoteObject.narrow( obj, HelloHome.class); /* * Use the factory to create the Hello EJB Object */ Hello hello = home.create(); /* * Call the hello() method on the EJB object. The * EJB object will delegate the call to the bean, * receive the result, and return it to us. * * We then print the result to the screen. */ System.out.println(hello.hello()); /* * Done with EJB Object, so remove it. * The container will destroy the EJB object. */ hello.remove();

}

}

To run the client: $ java -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory

© 2006, Watsh Rajneesh. All Rights Reserved.

20/86

2/9/2008

-Djava.naming.provider.url=corbaloc::localhost:3700/NameService examples.HelloClient Hello, World! We need to identify the initial context factory class in the naming service provider we use and the url for the root of the naming service.

To Remember…
If your bean calls another bean’s method and wants to pass its referecence as a parameter, then you must pass a reference to your bean’s EJB object, rather than a reference to your bean ie passing this wont work rather use the context object and call sessionCtx.getEJBObject() to get a reference to your EJB object and pass that as a reference, where sessionCtx is the priavate variable where you stored the session context object in the body of setSessionContext(). Also to allow for compile time checks for your bean class whether it implements all the business methods or not, pull out the business methods into a separate interface which can be extends by your remote and local interfaces and that your bean class will implement.
// Business interface public interface HelloBusinessMethods { public String hello() throws java.rmi.RemoteException; } // EJB remote interface public interface HelloRemote extends javax.ejb.EJBObject, HelloBusinessMethods { } // EJB local interface public interface HelloLocal extends javax.ejb.EJBLocalObject, HelloBusinessMethods { } // Bean implementation – now checked at compile time for compliance with the business methods interface public class HelloBean implements SessionBean, HelloBusinessMethods { public String hello() { return “Hello, World!”; } <...define other required callbacks...> }

Webservices using Stateless Session Beans
Web Services are a way of building a Service-Oriented Architecture (SOA). SOA is an architectural approach to structuring large-scale, distributed applications that integrate heterogeneous applications behind service interfaces. A service provider creates an abstract service definition that it publishes in a service registry. With Web Services, the description is a Web Services Definition Language (WSDL) file, and the registry follows the Universal Description, Discovery, and Integration (UDDI) standard. A service requestor can find the service description, possibly using a set of selection criteria to query the registry. If a suitable description is found, the requestor can bind to the service. SOAs emphasize modularity through standardized interfaces, flexibility through looser coupling, and extensibility through using XML. All of this is important in the B2B scenarios, which are the primary targets of Web Services.

© 2006, Watsh Rajneesh. All Rights Reserved.

21/86

2/9/2008

Web Services = WSDL + SOAP + UDDI

WSDL
wscompile – tool to generate WSDL from Java interface. Webservices are managed by container. JSR921 defines the programming model for webservices. It defines a port component for the server-side view of a web service. It is a portable java implementation of a service interface (port) and comprises java mapping of the service interface and the implementation bean. Writing web service using EJB requires creating one or more port components as stateless session beans. After exposing the bean as a web service only repackaging and redeploying is required, which now contains a port component. The EJB container will know how to dispatch incoming SOAP messages to our bean implementation and how to map the incoming XML data types to Java. The way to implement the service endpoint in an existing bean is to define the business methods interface separately and have the remote intrerface and the bean class implement this interface (as described earlier to provide compile time checking of business methods being implemented in the bean class): package examples; /** * This is the Hello remote interface. * */ public interface HelloInterface extends java.rmi.Remote { /** * The one method - hello - returns a greeting to the client. */ public String hello() throws java.rmi.RemoteException; } The extends java.rmi.Remote is added to the new definition of Hello interface. Remember that this interface is extended by Hello remote interface (which also extends javax.ejb.EJBObject). This interface is also called the Service Endpoint Interface (SEI).

© 2006, Watsh Rajneesh. All Rights Reserved.

22/86

2/9/2008

Note: The bean class may not implement this interface explicitly but the business methods in the SEI must anyhow be implemented by the bean class. JAX/RPC defines a mapping between a set of supported Java types and WSDL/XML types. Java primitive types are directly supported by JAX/RPC. Some non primitive types supported are: Wrappers (Boolean, Integer, Character, etc), java.net.URI, java.util.Calendar, java.util.Date and java.lang.String. Generate a JAX-RPC mapping file and WSDL: $ wscompile.bat -classpath ./classes -define ./assemble/mapping.xml src/config.xml -d ./assemble -nd ./assemble –mapping

Where, Config.xml: <?xml version="1.0" encoding="UTF-8"?> <configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config"> <service name="HelloWorldWS" targetNamespace="urn:examples" typeNamespace="urn:examples" packageName="examples"> <interface name="examples.HelloInterface"/> </service> </configuration> Config.xml defines the name of the service, the target namespace to use in the WSDL xml schema, the name of the SEI. Usage: wscompile [options] configuration_file -classpath <path> -define -d <directory> -nd <directory> -mapping <file> Specifies where to find input class files. Define a service Specifies where to place generated output files Specifies where to place non-class generated files Write the 109 mapping file to the given file

Following is the generated mapping file: <?xml version="1.0" encoding="UTF-8"?> <java-wsdl-mapping xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"> <package-mapping> <package-type>examples</package-type> <namespaceURI>urn:examples</namespaceURI> </package-mapping> <service-interface-mapping> <service-interface>examples.HelloWorldWS</service-interface> <wsdl-service-name xmlns:serviceNS="urn:examples">serviceNS:HelloWorldWS</wsdl-servicename> <port-mapping> <port-name>HelloInterfacePort</port-name> <java-port-name>HelloInterfacePort</java-port-name> </port-mapping> </service-interface-mapping>

© 2006, Watsh Rajneesh. All Rights Reserved.

23/86

2/9/2008

<service-endpoint-interface-mapping> <service-endpoint-interface>examples.HelloInterface</service-endpoint-interface> <wsdl-port-type xmlns:portTypeNS="urn:examples"> portTypeNS:HelloInterface </wsdl-port-type> <wsdl-binding xmlns:bindingNS="urn:examples"> bindingNS:HelloInterfaceBinding </wsdl-binding> <service-endpoint-method-mapping> <java-method-name>hello</java-method-name> <wsdl-operation>hello</wsdl-operation> <wsdl-return-value-mapping> <method-return-value>java.lang.String</method-return-value> <wsdl-message xmlns:wsdlMsgNS="urn:examples"> wsdlMsgNS:HelloInterface_helloResponse </wsdl-message> <wsdl-message-part-name>result</wsdl-message-part-name> </wsdl-return-value-mapping> </service-endpoint-method-mapping> </service-endpoint-interface-mapping> </java-wsdl-mapping> Generate the client stub classes: $ wscompile.bat -classpath ./classes -gen:client -keep -d ./src/generated -nd ./classes src/config.xml warning: You have specified : -gen:both or -gen:client with a SEI. The use of these modes are recommended with WSDL only. Where, -keep Keep generated files -gen:client Generate client artifacts (stubs, etc). Create a webservices.xml Deployment descriptor: <?xml version="1.0" encoding="UTF-8"?> <webservices xmlns="http://java.sun.com/xml/ns/j2ee" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"> <webservice-description> <display-name>HelloService</display-name> <webservice-description-name>HelloWS</webservice-description-name> <wsdl-file>META-INF/wsdl/HelloWorldWS.wsdl</wsdl-file> <jaxrpc-mapping-file>META-INF/wsdl/mapping.xml</jaxrpc-mapping-file> <port-component> <display-name>HelloWS</display-name> <port-component-name>HelloWS</port-component-name> <wsdl-port xmlns:wsdl-port_ns__="urn:examples">wsdl-port_ns__:HelloInterfacePort</wsdl-port> <service-endpoint-interface>examples.HelloInterface</service-endpoint-interface> <service-impl-bean> <ejb-link>HelloBean</ejb-link> </service-impl-bean> </port-component> </webservice-description> </webservices> And package everything together in the ejb jar file as shown below:

© 2006, Watsh Rajneesh. All Rights Reserved.

24/86

2/9/2008

Deploy this jar in the usual way and access it at url ??. (This part will be completed after I have read the J2EE Webservices book).

Entity Beans
Entity beans are persistent objects.
public interface javax.ejb.EntityBean extends javax.ejb.EnterpriseBean { public void setEntityContext(javax.ejb.EntityContext); public void unsetEntityContext(); public void ejbRemove(); public void ejbActivate(); public void ejbPassivate(); public void ejbLoad(); public void ejbStore(); }

Object-Relational Mapping : Mapping of objects to relational databases. Eg of ORM products are Hibernate, Oracle TopLink, JDO etc. Entity beans can persist themselves in many ways, including Java serialization, O/R mapping, or even an object database persistence. O/R mappings are the most frequently used mechanism in practice. Two files constitute an entity bean: 1. entity bean class: maps to the entity definition in a database schema. 2. primary key class: is an object that may contain any number of attributes (like composite primary key). This could be any data necessary to identify uniquely an entity bean data instance. It must be serializable. Entity beans lifetime depends on how long the data sits in the database. Entity beans are generally accessed by other beans that run-in process (typically with a session façade in which case a session bean will access the entity bean). Clients (servlets/jsp/applets) invoke a method on the session façade and the session bean in turn calls the entity bean. Since the session and entity beans will be

© 2006, Watsh Rajneesh. All Rights Reserved.

25/86

2/9/2008

colocated in the same JVM process so the entity beans only expose local interface in production (and not remote).

Load and Store
ejbLoad() : reads the data in from the persistent storage into the entity bean’s in-memory fields. ejbStore() : saves your bean instance’s current fields to the underlying data storage. The container automatically synchronizes the in-memory entity bean instance with the database record they represent by calling ejbLoad() and ejbStore() callbacks. There can be multiple in-memory entity bean instances which represent the same underlying data. The data corruption is prevented in such circumstances by synchronizing the beans with the underlying storage. The frequency of such synchronizations is determined by the transaction isolation level associated with the bean. If it is read-commited then two clients accessing the entity bean instances mapped to same data can read the data only when the modification to it has been saved/committed to the storage. An uncommitted data change will not be read. The container may pool and reuse the entity bean instances to represent different instances of the same type of data in the database (eg. Entity bean instance to represent different bank account records). Reassigning the entity bean instance to represent a different data record requires having to let the bean know to release any resource it held while mapping to the older data record. For this, entity bean class will need to implement ejbActivate() and ejbPassivate(). The container invokes ejbStore() before passivating the bean and invokes ejbLoad() after activating the bean.

Types
Bean Managed Persistent entity beans require you to write code to translate your in-memory fields into an underlying data store. You need to provide implementations for ejbCreate(), ejbLoad(), ejbStore(), ejbFindXXX() and ejbRemove() methods using JDBC API. Container Managed Persistent entity beans requires you to provide the entity bean O/R mapping in the deployment descriptor and container generates the data access code.

Create and Remove
When an entity bean is initialized in memory during ejbCreate(), a new data record is inserted to the underlying database that correlates with the in-memory instance. ejbRemove() should then delete the data record from the database. Bean return a primary key to the container so that the container can identify the bean uniquely, upon ejbCreate() being called. On ejbRemove(), the database data associated with the bean is deleted and the bean is made inaccessible to the client. Client can call remove() method of either EJBObject or Home object.
In bean class: public AccountPK ejbCreate(String accountID, String owner) throws... In home interface: public Account create(String accountID, String owner) throws ...

Home interface exposes finder methods in addition to create and remove methods. If you directly create/modify/delete the data by directly touching the database, the in-memory entity beans will be created (by just calling findByPrimaryKey() method on the home object for your bean), modified (upon automatic synchronization) and deleted. So its not necessary for an entity bean to have an ejbCreate() method as they can be created by directly touching the database.

© 2006, Watsh Rajneesh. All Rights Reserved.

26/86

2/9/2008

Entity Context
An entity bean has a context object (which implements javax.ejb.EntityContext) via which it can query the container for its own transaction state and security information.
public interface javax.ejb.EJBContext { public javax.ejb.EJBHome getEJBHome(); public javax.ejb.EJBLocalHome getEJBLocalHome(); public java.security.Principal getCallerPrincipal(); public boolean isCallerInRole(java.lang.String); public void setRollbackOnly(); public boolean getRollbackOnly(); } public interface javax.ejb.EntityContext extends javax.ejb.EJBContext { public javax.ejb.EJBLocalObject getEJBLocalObject(); public javax.ejb.EJBObject getEJBObject(); public java.lang.Object getPrimaryKey(); // new in entity context }

getPrimaryKey() :
You call it whenever you want to figure out with which database data your instance is associated. Your entity bean must perform a getPrimaryKey() callback to the entity context to figure out what data it is dealing with. (Remember: entity beans can be pooled and reused to cater to different data records). In case of BMP, you will need to use it for the following method implementations: 1. ejbLoad() : when ejbStore() is called the bean has the knowledge of what data it holds but when the container calls its ejbLoad() it should first use getPrimaryKey() to know what data to be fetched from the database. 2. ejbRemove() : when ejbCreate() is called the bean knows what data to create as it has been passed to it in parameters to ejbCreate(). But while removing the data, you must call the getPrimaryKey() to find out what data to remove.

Finder methods:
Are defined on local/remote home interfaces and implemented by your bean implementations to find one or more existing entity bean in storage. You must define atleast one finder method – ejbFindByPrimaryKey(). For eg. You might perform a query as “SELECT id FROM accounts WHERE balance > 10000” and return the primary keys for the resultset data back to the container by creating one or more primary key object instances. Container will then create EJB objects for the client to invoke on and possibly associate some entity bean instances with those EJB objects. public Collection ejbFindBigAccounts() throws FinderException { //… } Collection is collection of primary keys. Container then creates a collection of EJB Objects one for each primary key in the collection, and returns those EJB Objects in its own collection to the client. 1. All finder methods must being with ejbFind. 2. Must have atleast one finder method – ejbFindByPrimaryKey(). public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException { //… } Note: You define finder methods only in case of BMP. For CMP, these method implementations are generated by container.

© 2006, Watsh Rajneesh. All Rights Reserved.

27/86

2/9/2008

Clients invoke finder methods on home objects. Entity bean instance returns a primary key to the container, whereas the home object returns an EJB Object to the client.

Bean Managed Persistent (BMP) Entity Beans
You are responsible to provide the implementation to map your entity bean instances to and from storage. To do this you either use: 3. JDBC API or 4. ORM framework – Hibernate or Oracle TopLink. Steps to follow: 5. setEntityContext() – store the entity context in a member varible. After this method executes, bean does not hold a data yet but is available in pool. 6. ejbFindXXX() – as explained earlier. 7. ejbHomeXXX() – methods on an entity bean that are not specific to any data record. Eg. Counting the total number of records in a table. They are special business methods, as they are called from bean in pool before the bean is associated with any data. Clients call home methods from local/remote home objects. 8. ejbCreate() – you may not write any ejbCreate if you don’t want EJB clients to be able to create new database data. These methods are responsible for creating new data record and initializing your bean. For BMP, you can use INSERT SQL statement to create new data and return an instance of primary key for the data to the container. 9. ejbPostCreate() – must define one ejbPostCreate() for each ejbCreate() and both should take the same parameters. 1. You can do any post initialization work here and/or 2. pass the reference to your bean’s EJB Object to other beans and/or 3. reset certain transaction related parameteres.  ejbActivate() – acquire any resource (such as socket conncetions) if needed.  ejbLoad() – Call getPrimaryKey() on entity context to know what data to load and then read the data (SQL SELECT) into your bean.  ejbStore() – write your member fields out to disk through SQL UPDATE.  ejbPassivate() – release any resource if needed.  ejbRemove() – Call getPrimaryKey() on entity context to know what data to delete from the database then delete (SQL DELETE) the data.  unsetEntityContext() – release any resource aquired in setEntityContext() and get ready to be garbage collected. Called when entity bean instance is to be destroyed by container when it wants to reduce its pool size.

© 2006, Watsh Rajneesh. All Rights Reserved.

28/86

2/9/2008

BMP Entity bean with local interface

We are not showing the code for the remote interface below but for testing we use the remote interface itself. Though in practice, we will use a session façade to interface remotely with the client and use the entity beans locally but to test the entity bean individually without writing a session façade we use the remote interface.

Local interface
package examples.bmp; import javax.ejb.*; /** * This is the local interface for AccountBean. * * Local clients interact with beans through this interface. The container will * implement this interface; the implemented object is called the local object, * which delegates invocations to the actual bean. */ public interface AccountLocal extends EJBLocalObject { /** * Deposits amt into account. */ public void deposit(double amt) throws AccountException; /** * Withdraws amt from bank account. * @throw AccountException thrown if amt > available balance */ public void withdraw(double amt) throws AccountException; // Getter/setter methods on Entity Bean fields public double getBalance(); public String getOwnerName(); public void setOwnerName(String name); public String getAccountID(); public void setAccountID(String id);

© 2006, Watsh Rajneesh. All Rights Reserved.

29/86

2/9/2008

}

Local Home Interface
package examples.bmp; import javax.ejb.*; import java.util.Collection; /** * This is the local home interface for Account. This * interface is implemented by the EJB container’s tools - the * implemented object is called the local home object, which * is a factory for local EJB objects. */ public interface AccountLocalHome extends EJBLocalHome { /** * We define a single create() method in this home interface, * which corresponds to the ejbCreate() method in AccountBean. * This method creates the local EJB object. * * Notice that the local home interface returns a * local interface, whereas the bean returns a PK. * * Notice we don’t throw RemoteExceptions because we are local not remote. * * @param accountID The number of the account (unique) * @param ownerName The name of the person who owns the account * @return The newly created local object. */ public AccountLocal create(String accountID, String ownerName) throws CreateException; /** * Finds an Account by its primary Key (Account ID) */ public AccountLocal findByPrimaryKey(AccountPK key) throws FinderException; /** * Finds all Accounts under an owner’s name */ public Collection findByOwnerName(String name) throws FinderException; /** * This home business method is independent of any particular * account instance. It returns the total of all the bank * accounts in the bank. */ public double getTotalBankValue() throws AccountException;

}

Primary Key class
package examples.bmp; /** * Primary Key class for Account. */ public class AccountPK implements java.io.Serializable { public String accountID; public AccountPK(String id) { this.accountID = id; } public AccountPK() { } public String toString() { return accountID; } public int hashCode() { return accountID.hashCode(); } public boolean equals(Object account) {

© 2006, Watsh Rajneesh. All Rights Reserved.

30/86

2/9/2008

}

}

if (!(account instanceof AccountPK)) return false; return ((AccountPK)account).accountID.equals(accountID);

Primary key contains a simple string but its possible for an entity bean to map to more than one table in the database and may have primary key class that have several field inside them, each representing a primary key of a table in the database. hashCode() and equals() should be overridden to allow the container to be able to compare two primary key instances by value when stored in a HashMap.

Custom Exception (Application Level)
package examples.bmp; /** * Exceptions thrown by Accounts */ public class AccountException extends Exception { public AccountException() { super(); } public AccountException(Exception e) { super(e.toString()); } public AccountException(String s) { super(s); } }

Entity Bean Class
create table accounts (id varchar(64), ownername varchar(64), balance numeric(18) ); is the table schema to which the entity bean class maps. package examples.bmp; import java.sql.*; import javax.naming.*; import javax.ejb.*; import java.util.*; /** * Demonstration Bean-Managed Persistent Entity Bean. This Entity Bean * represents a Bank Account. */ public class AccountBean implements EntityBean { protected EntityContext ctx; // // Bean-managed state fields // private String accountID; // PK private String ownerName; private double balance; public AccountBean() { System.out.println(“New Bank Account Entity Bean Java Object created by EJB Container.”); } // // Business Logic Methods // /** * Deposits amt into account. */ public void deposit(double amt) throws AccountException { System.out.println(“deposit(“ + amt + “) called.”); balance += amt; }

© 2006, Watsh Rajneesh. All Rights Reserved.

31/86

2/9/2008

/** * Withdraws amt from bank account. * @throw AccountException thrown if amt > available balance */ public void withdraw(double amt) throws AccountException { System.out.println(“withdraw(“ + amt + “) called.”); if (amt > balance) { throw new AccountException(“Your balance is “ + balance + “! You cannot withdraw “ + amt + “!”); } balance -= amt; } // Getter/setter methods on Entity Bean fields public double getBalance() { System.out.println(“getBalance() called.”); return balance; } public void setOwnerName(String name) { System.out.println(“setOwnerName() called.”); ownerName = name; } public String getOwnerName() { System.out.println(“getOwnerName() called.”); return ownerName; } public String getAccountID() { System.out.println(“getAccountID() called.”); return accountID; } public void setAccountID(String id) { System.out.println(“setAccountID() called.”); this.accountID = id; } /** * This home business method is independent of any * particular account instance. It returns the total * of all the bank accounts in the bank. */ public double ejbHomeGetTotalBankValue() throws AccountException { PreparedStatement pstmt = null; Connection conn = null; try { System.out.println(“ejbHomeGetTotalBankValue()”); /* Acquire DB connection */ conn = getConnection(); /* Get the total of all accounts */ pstmt = conn.prepareStatement(“select sum(balance) as total from accounts”); ResultSet rs = pstmt.executeQuery(); /* Return the sum */ if (rs.next()) { return rs.getDouble(“total”); } } catch (Exception e) { e.printStackTrace(); throw new AccountException(e); } finally { /* * Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } throw new AccountException(“Error!”); }

© 2006, Watsh Rajneesh. All Rights Reserved.

32/86

2/9/2008

/** * Gets JDBC connection from the connection pool. * * @return The JDBC connection */ public Connection getConnection() throws Exception { try { Context ctx = new InitialContext(); javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup(“java:comp/env/jdbc/ejbPool”); return ds.getConnection(); } catch (Exception e) { System.err.println(“Couldn’t get datasource!”); e.printStackTrace(); throw e; } } // // EJB-required methods // /** * Called by Container. Implementation can acquire * needed resources. */ public void ejbActivate() { System.out.println(“ejbActivate() called.”); } /** * Removes entity bean data from the database. * Corresponds to when client calls home.remove(). */ public void ejbRemove() throws RemoveException { System.out.println(“ejbRemove() called.”); /* * Remember that an entity bean class can be used to * represent different data instances. So how does * this method know which instance in the database * to delete? * * The answer is to query the container by calling * the entity context object. By retrieving the * primary key from the entity context, we know * which data instance, keyed by the PK, that we * should delete from the DB. */ AccountPK pk = (AccountPK) ctx.getPrimaryKey(); String id = pk.accountID; PreparedStatement pstmt = null; Connection conn = null; try { /* * 1) Acquire a new JDBC Connection */ conn = getConnection(); /* * 2) Remove account from the DB */ pstmt = conn.prepareStatement(“delete from accounts where id = ?”); pstmt.setString(1, id); /* * 3) Throw a system-level exception if something * bad happened. */ if (pstmt.executeUpdate() == 0) { throw new RemoveException( “Account “ + pk + “ failed to be removed from the database”); } } catch (Exception ex) {

© 2006, Watsh Rajneesh. All Rights Reserved.

33/86

2/9/2008

} finally {

throw new EJBException(ex.toString()); /* * 4) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } }

} /** * Called by Container. Releases held resources for * passivation. */ public void ejbPassivate() { System.out.println(“ejbPassivate () called.”); } /** * Called by the container. Updates the in-memory entity * bean object to reflect the current value stored in * the database. */ public void ejbLoad() { System.out.println(“ejbLoad() called.”); /* * Again, query the Entity Context to get the current * Primary Key, so we know which instance to load. */ AccountPK pk = (AccountPK) ctx.getPrimaryKey(); String id = pk.accountID; PreparedStatement pstmt = null; Connection conn = null; try { /* * 1) Acquire a new DB Connection */ conn = getConnection(); /* * 2) Get account from the DB, querying * by account ID */ pstmt = conn.prepareStatement(“select ownerName, balance from accounts “ + “where id = ?”); pstmt.setString(1, id); ResultSet rs = pstmt.executeQuery(); rs.next(); ownerName = rs.getString(“ownerName”); balance = rs.getDouble(“balance”); } catch (Exception ex) { throw new EJBException( “Account “ + pk + “ failed to load from database”, ex); } finally { /* * 3) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } } /** * Called from the Container. Updates the database * to reflect the current values of this in-memory

© 2006, Watsh Rajneesh. All Rights Reserved.

34/86

2/9/2008

* entity bean instance. */ public void ejbStore() { System.out.println(“ejbStore() called.”); PreparedStatement pstmt = null; Connection conn = null; try { /* * 1) Acquire a new DB Connection */ conn = getConnection(); /* * 2) Store account in DB */ pstmt = conn.prepareStatement( “update accounts set ownerName = ?, balance = ?” + “ where id = ?”); pstmt.setString(1, ownerName); pstmt.setDouble(2, balance); pstmt.setString(3, accountID); pstmt.executeUpdate(); } catch (Exception ex) { throw new EJBException(“Account “ + accountID + “ failed to save to database”, ex); } finally { /* * 3) Release the DB Connection */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } } /** * Called by the container. Associates this bean * instance with a particular context. We can query * the bean properties that customize the bean here. */ public void setEntityContext(EntityContext ctx) { System.out.println(“setEntityContext called”); this.ctx = ctx; } /** * Called by Container. Disassociates this bean * instance with a particular context environment. */ public void unsetEntityContext() { System.out.println(“unsetEntityContext called”); this.ctx = null; } /** * Called after ejbCreate(). Now, the Bean can retrieve * its EJBObject from its context, and pass it as * a ‘this’ argument. */ public void ejbPostCreate(String accountID, String ownerName) { } /** * This is the initialization method that corresponds to the * create() method in the Home Interface. * * When the client calls the Home Object’s create() method, * the Home Object then calls this ejbCreate() method. * * @return The primary key for this account */ public AccountPK ejbCreate(String accountID, String ownerName) throws CreateException {

© 2006, Watsh Rajneesh. All Rights Reserved.

35/86

2/9/2008

} /** * Finds a Account by its primary Key */ public AccountPK ejbFindByPrimaryKey(AccountPK key) throws FinderException { PreparedStatement pstmt = null; Connection conn = null; try { System.out.println(“ejbFindByPrimaryKey(“+ key + “) called”); /* * Acquire DB connection */ conn = getConnection(); /* * Find the Entity in the DB */ pstmt = conn.prepareStatement(“select id from accounts where id = ?”); pstmt.setString(1, key.toString()); ResultSet rs = pstmt.executeQuery(); rs.next(); /* * No errors occurred, so return the Primary Key */ return key; } catch (Exception e) { throw new FinderException(e.toString()); } finally { /* * Release DB Connection for other beans

PreparedStatement pstmt = null; Connection conn = null; try { System.out.println(“ejbCreate() called.”); this.accountID = accountID; this.ownerName = ownerName; this.balance = 0; /* * Acquire DB connection */ conn = getConnection(); /* * Insert the account into the database */ pstmt = conn.prepareStatement( “insert into accounts (id, ownerName, balance)” + “ values (?, ?, ?)”); pstmt.setString(1, accountID); pstmt.setString(2, ownerName); pstmt.setDouble(3, balance); pstmt.executeUpdate(); /* * Generate the Primary Key and return it */ return new AccountPK(accountID); } catch (Exception e) { throw new CreateException(e.toString()); } finally { /* * Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } }

© 2006, Watsh Rajneesh. All Rights Reserved.

36/86

2/9/2008

}

} } /** * Finds Accounts by name */ public Collection ejbFindByOwnerName(String name) throws FinderException { PreparedStatement pstmt = null; Connection conn = null; Vector v = new Vector(); try { System.out.println(“ejbFindByOwnerName(“ + name + “) called”); /* * Acquire DB connection */ conn = getConnection(); /* * Find the primary keys in the DB */ pstmt = conn.prepareStatement( “select id from accounts where ownerName = ?”); pstmt.setString(1, name); ResultSet rs = pstmt.executeQuery(); /* * Insert every primary key found into a vector */ while (rs.next()) { String id = rs.getString(“id”); v.addElement(new AccountPK(id)); } /* * Return the vector of primary keys */ return v; } catch (Exception e) { throw new FinderException(e.toString()); } finally { /* * Release DB Connection for other beans */ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } }

*/ try { if (pstmt != null) pstmt.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { }

Deployment Descriptor
<?xml version=”1.0” encoding=”UTF-8”?> <ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <display-name>AccountJAR</display-name> <enterprise-beans> <entity> <ejb-name>AccountEJB</ejb-name> <home>examples.bmp.AccountHome</home> <remote>examples.bmp.Account</remote> <ejb-class>examples.bmp.AccountBean</ejb-class> <persistence-type>Bean</persistence-type>

© 2006, Watsh Rajneesh. All Rights Reserved.

37/86

2/9/2008

<prim-key-class>examples.bmp.AccountPK</prim-key-class> <reentrant>false</reentrant> <resource-ref> <res-ref-name>jdbc/bmp-account</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> <res-sharing-scope>Shareable</res-sharing-scope> </resource-ref> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>AccountEJB</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <method> <ejb-name>AccountEJB</ejb-name> <method-intf>Local</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>

Persistence-type Prim-key-class Reentrant Resource-ref Assembly-descriptor

Bean/Container Primary key class Whether our bean can call itself through another bean. A given bean A is reentrant if it calls bean B which calls back on bean A. Sets up our jdbc driver at jndi location Associates transactions with out bean.

You will also need the AppServer specific deployement descriptor where you can configure the remote and local home interface and the JDBC driver with JNDI locations. <?xml version="1.0" encoding="UTF-8"?> <!-Copyright 2004 Sun Microsystems, Inc. All rights reserved. SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. --> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.0 EJB 2.1//EN" "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_2_1-0.dtd"> <sun-ejb-jar> <enterprise-beans> <name>BMPEntityEjb.jar</name> <unique-id>0</unique-id> <ejb> <ejb-name>AccountEJB</ejb-name> <jndi-name>AccountHome</jndi-name> <resource-ref> <res-ref-name>jdbc/bmp-account</res-ref-name> <jndi-name>jdbc/bmp-account</jndi-name> </resource-ref> <bean-pool> <steady-pool-size>0</steady-pool-size> </bean-pool> </ejb>

© 2006, Watsh Rajneesh. All Rights Reserved.

38/86

2/9/2008

</enterprise-beans> </sun-ejb-jar> Create the accounts table in the database using the sql file provided. This step is database specific. Create EJB jar to deploy: >mkdir assemble\ejbjar Put the ejb-jar.xml and sun-ejb-jar.xml in the meta-inf folder in classes. >jar cvf BMPEntityEJB.jar –C classes . >move BMPEntityEJB.jar assemble\ejbjar

Client Code
package examples.bmp; import javax.ejb.*; import javax.naming.*; import java.rmi.*; import javax.rmi.*; import java.util.*; /** * Sample client code that manipulates a Bank Account Entity Bean. */ public class AccountClient { public static void main(String[] args) throws Exception { Account account = null; try { /* * Get a reference to the Account Home Object - the * factory for Account EJB Objects */ Context ctx = new InitialContext(System.getProperties()); Object obj = ctx.lookup(“AccountHome”); AccountHome home = (AccountHome)PortableRemoteObject.narrow(obj, AccountHome.class); System.err.println(“Total of all accounts in bank initially = “ + home.getTotalBankValue()); /* Use the factory to create the Account EJB Object */

© 2006, Watsh Rajneesh. All Rights Reserved.

39/86

2/9/2008

}

}

} catch (Exception e) { System.out.println(“Caught exception!”); e.printStackTrace(); } finally { /* * Destroy the Entity permanently */ try { System.out.println(“Destroying account..”); if (account != null) { account.remove(); } } catch (Exception e) { e.printStackTrace(); } }

home.create(“123-456-7890”, “John Smith”); /* Find an account */ Iterator i = home.findByOwnerName(“John Smith”).iterator(); if (i.hasNext()) { account =(Account)javax.rmi.PortableRemoteObject.narrow(i.next(), Account.class); } else { throw new Exception(“Could not find account”); } /* Call the balance() method, and print it */ System.out.println(“Initial Balance = “ + account.getBalance()); /* Deposit $100 into the account */ account.deposit(100); /* Retrieve the resulting balance. */ System.out.println(“After depositing 100, account balance = “ + account.getBalance()); System.out.println(“Total of all accounts in bank now = “ + home.getTotalBankValue()); /* Retrieve the Primary Key from the EJB Object */ AccountPK pk = (AccountPK) account.getPrimaryKey(); /* * Release our old EJB Object reference. Now call * find() again, this time querying on Account ID * (i.e. the Primary Key). */ account = null; account = home.findByPrimaryKey(pk); /* Print out current balance */ System.out.println(“Found account with ID “ + pk + “. Balance = “ + account.getBalance()); /* Try to withdraw $150 */ System.out.println(“Now trying to withdraw $150, which is more “+ “than is currently available. This should “+ “generate an exception..”); account.withdraw(150);

Run the client: Generate the Client Jar: >rmic -classpath .\classes;d:\Sun\AppServer\lib\j2ee.jar;d:\Sun\AppServ\lib\appserv-ext.jar -iiop examples.bmp.Account >rmic -classpath .\classes;d:\Sun\AppServer\lib\j2ee.jar;d:\Sun\AppServ\lib\appserv-ext.jar -iiop examples.bmp.AccountHome >mkdir assemble\client

© 2006, Watsh Rajneesh. All Rights Reserved.

40/86

2/9/2008

>jar cvf BMPEntityClient.jar –C classes . >move BMPEntityClient.jar .\assemble\client >java -cp .\assemble\client\BMPEntityClient.jar\;%CLASSPATH% -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory -Djava.naming.provider.url=corbaloc::localhost:3700/NameService examples.bmp.AccountClient

10. Container calls newInstance() on the bean class to create an instance of bean. This calls entity
bean’s default constructor. Container associates the bean instance with an entity context by calling setEntityContext() method of bean class. Now the bean is put in the instance pool for that entity bean type. In the pool, the bean instance can be used to find entity data in the database by servicing a finder method on behalf of client. It can also perform operations not dependent on a particular data instance by servicing ejbHome() method. Container can call the unsetEntityContext() when it wants to destroy the bean instance from pool (and the bean will be ready for garbage collection). When client wants to create some new database data then it calls the create() method on the home interface. Container grabs an entity bean from pool and calls its ejbCreate() method where the bean initializes itself to a specific data set passed in the params of the create() method by the client and, in case of BMP, this method will also create the corresponding data record in the database. Now the bean moves to ready state.

11.

12.

© 2006, Watsh Rajneesh. All Rights Reserved.

41/86

2/9/2008

13. In the ready state, your bean is tied to a specific data and hence a specific EJB Object. Container
may occassionally need to synchronize your bean instance with the database by calling ejbLoad() and ejbStore(). So ejbLoad() and ejbStore() will be responsible for loading and saving the data in the database, in case of BMP. If the client calls remove() on the home object or EJB object then container will call the ejbRemove() method which in case of BMP is supposed to delete the database data associated with this bean instance. If the container needs to reuse a bean instance in the ready state to service another client, then it will need to passivate the bean in which case it will call the ejbStore() method and then the ejbPassivate() method, where the bean can release any resource it held. Then the bean is returned back to pool for reuse. Container may want to reassign the bean to an existing EJB object, then it will call the ejbActivate() on the bean where the bean can reaquire the resouces it held earlier, and then the container calls the ejbLoad() where the bean can initialize itself to the specific data (by first learning about what primary key to use to retrieve that unique data record from the EJB object).

14. 15.

16.

Container Managed Persistent (CMP) Entity Beans
With CMP, you don’t implement any persistence logic in the bean itself; rather the EJB container generates the required storage code by subclassing your entity bean class. Thus all CMP entity beans comprise of two classes: the superclass which you write (containing the entity bean business logic); and the subclass which the container generates (which contains the persistence logic). You don’t define any persistent fields and the associated get/set methods in your bean. They are kept in the subclass (which the container generates). You will need to declare the get/set methods as abstract methods in your entity bean class (thus making it an abstract class). So if you need to provide a business method which works on more than one persistent field then you can define such a method in your entity bean class itself and use the abstract get/set methods in your implementation which will resolve to the subclasses implementation of those get/set methods at runtime. For example,
// CMP superclass – you write. public abstract class CartBean implements EntityBean { // no fields // abstract get/set methods public abstract float getSubTotal(); public abstract float getTaxes(); // other business methods public float getTotal() { return this.getSubtotal() + this.getTaxes(); } } // EJB required methods follow

// CMP subclass – container generated. public class CartBeanSubClass extends CartBean { // fields … public float subTotal; public float taxes; … public float getSubTotal() { return subTotal; } public float getTaxes() { return taxes;

© 2006, Watsh Rajneesh. All Rights Reserved.

42/86

2/9/2008

}

} // other get/set method implementations

Abstract Persistence Schema
... <cmp-version>2.x</cmp-version> <abstract-schema-name>AccountBean</abstract-schema-name> <cmp-field> <field-name>accountID</field-name> </cmp-field> <cmp-field> <field-name>ownerName</field-name> </cmp-field> <cmp-field> <field-name>balance</field-name> </cmp-field> <primkey-field>accountID</primkey-field> ...

Abstract persistence schema is defined in the ejb-jar.xml to let the container know what to generate for the persistence logic. The container derieves the type of these fields from the get/set abstract methods.

EJB QL
EJB Query Language is an object-oriented SQL-like syntax for querying entity beans. You write EJB QL in the deployment descriptor and the container should be able to generate the corresponding database logic in SQL in a database specific way. For example, for the container to generate the implementation for the finder method – findBigAccounts() we need to tell the container what query to perform on the database (in a portable way using EJB QL in the DD) to generate the implementation for this method.
public Collection findBigAccounts(int minimum);

The EJB QL for this could be:
SELECT OBJECT(a) FROM Account as a WHERE a.balance > ?1

?1 – is the first parameter passed in to the method findBigAccounts viz minimum. Note: Not all fields have to be managed by container. You might be pulling data from secondary sources or you might have calculated fields. EJB container will notify your bean class during persistent operations allowing you to manage these fields.

ejbSelect() – only in CMP
An ejbSelect() method is a query method (like a finder method) but is not directly exposed to client in the home interface or component interface. It is used internally within an entity bean as a helper method to access a storage. It is useful when you have entity beans in relationships with external data, such as other entity beans. Your bean might hold references to other beans (in case of foreign key relationships). So one bean might use ejbSelect() to verify the referential integrity for its foreign key fields. Also the bean could use an ejbSelect() to implement a ejbHome() method (methods not related to any data instance) as shown below: public abstract class AccountBean implements javax.ejb.EntityBean { public abstract Collection ejbSelectAllAccountBalances() throws FinderException;

© 2006, Watsh Rajneesh. All Rights Reserved.

43/86

2/9/2008

public double ejbHomeGetTotalBankValue() throws Exception { // get a collection of bank account balances Collection c = this.ejbSelectAllAccountBalances(); // loop through the collection and return sum } } We can tell the container how to write the ejbSelectAllAccountBalances() method just like we do for finder methods – using EJB QL in the DD. SELECT OBJECT(a) FROM Account AS a WHERE a.balance IS NOT NULL

1. ejbSelect() methods are used internally within the bean and not exposed to clients.
2. Can retrieve data from other entity beans that you have relationship with. container managed fields (a.balance above) which finder methods cannot (they must only return primary key or collection of primary keys). The remote, home, local and local home interfaces and primary key class remain same for both BMP and CMP. What changes is the bean class code and the deployement descriptor. The client code does not change if we change between BMP and CMP implementations. Steps to follow for CMP entity bean coding: (differences from BMP highlighted in red). 17. setEntityContext() – store the entity context in a member varible. After this method executes, bean does not hold a data yet but is available in pool. 18. ejbFindXXX() – Donot write this method in bean class, for CMP. Use EJB QL and the container tools to tell the container what logic to execute when the client performs a finder method on the home object. 19. ejbSelectXXX() {only in CMP}– Define this method as abstract and provide the EJB QL in the deployment descriptor to set up the query. These are helper methods which perform queries internally by your bean and are not accessible to clients of your bean. 20. ejbHomeXXX() {partially similar to BMP}– methods on an entity bean that are not specific to any data record. Eg. Counting the total number of records in a table. They are special business methods, as they are called from bean in pool before the bean is associated with any data. Clients call home methods from local/remote home objects. For CMP, you provide this method in the bean class and do the JDBC code yourself or have the container do it for you by using the ejbSelectXXX() helper method mechanism described above for ejbHomeGetTotalBankValue(). 21. ejbCreate() – you may not write any ejbCreate if you don’t want EJB clients to be able to create new database data. These methods are responsible for creating new data record and initializing your bean. For CMP, donot create database data here, rather just validate the client’s initialization parameters and call your abstract set methods to initialize the generated bean subclass. Entity bean instance moves to the ready state with ejbCreate(). 22. ejbPostCreate() – must define one ejbPostCreate() for each ejbCreate() and both should take the same parameters. Its called after container has associated an EJB object with your bean instance (ie bean is in the ready state). You can get the primary key from the EJB object and use it here. 1. You can do any post initialization work here and/or 2. pass the reference to your bean’s EJB Object to other beans and/or 3. reset certain transaction related parameteres.  ejbActivate() – acquire any resource (such as socket conncetions) if needed.

3. Like finder methods, ejbSelect() methods can return primary key(s) or they can even return

© 2006, Watsh Rajneesh. All Rights Reserved.

44/86

2/9/2008

 

  

ejbLoad() – Don’t read data here. Container will do that right before it calls your ejbLoad(). Here you can perform any utilities you need to work with the read-in data (such as decompressing a text field etc) using the get/set abstract methods. ejbStore() – Don’t update the database here. Container will do that right after it calls you ejbStore() method. So in this method you can prepare (eg compressing a text field) your containermanaged fields (those in the subclass) to be written in the database using the get/set abstract methods. ejbPassivate() – release any resource if needed. ejbRemove() – Don’t delete the database data here. Container calls this method before actually deleting the data from the database itself. Just perform any operation that must be done before the data is destroyed. unsetEntityContext() – release any resource aquired in setEntityContext() and get ready to be garbage collected. Called when entity bean instance is to be destroyed by container when it wants to reduce its pool size.

Changing the previous example (for BMP) to use CMP, we just need to re-write the bean class and the deployment descriptor.

Bean Class Code
package examples.cmp; import javax.ejb.*; /** * Entity bean the demos CMP. */ public abstract class AccountBean implements EntityBean { protected EntityContext ctx; // no data fields public AccountBean() { System.out.println("New Bank Account Entity Bean Java Object created by EJB Container."); } //------------------// Begin abstract get/set methods //------------------public abstract double getBalance(); public abstract void setOwnerName(String name); public abstract String getOwnerName(); public abstract String getAccountID(); public abstract void setAccountID(String id); public abstract void setBalance(double balance); //------------------// End abstract get/set methods //------------------//------------------// Begin EJB required methods //------------------/** * Called by Container. Implementation can acquire * needed resources. */

© 2006, Watsh Rajneesh. All Rights Reserved.

45/86

2/9/2008

public void ejbActivate() { System.out.println("ejbActivate() called."); } /** * Removes entity bean data from the database. * Corresponds to when client calls home.remove(). */ public void ejbRemove() throws RemoveException { System.out.println("ejbRemove() called."); } /** * Called by Container. Releases held resources for * passivation. */ public void ejbPassivate() { System.out.println("ejbPassivate () called."); } /** * Called by the container. Updates the in-memory entity * bean object to reflect the current value stored in * the database. */ public void ejbLoad() { System.out.println("ejbLoad() called."); } /** * Called from the Container. Updates the database * to reflect the current values of this in-memory * entity bean instance. */ public void ejbStore() { System.out.println("ejbStore() called."); } /** * Called by the container. Associates this bean * instance with a particular context. We can query * the bean properties which customize the bean here. */ public void setEntityContext(EntityContext ctx) { System.out.println("setEntityContext called"); this.ctx = ctx; } /** * Called by Container. Disassociates this bean * instance with a particular context environment. */ public void unsetEntityContext() { System.out.println("unsetEntityContext called"); this.ctx = null; }

© 2006, Watsh Rajneesh. All Rights Reserved.

46/86

2/9/2008

/** * Called after ejbCreate(). Now, the Bean can retrieve * its EJBObject from its context, and pass it as * a 'this' argument. */ public void ejbPostCreate(String accountID, String ownerName) { } public AccountPK ejbCreate(String accountID, String ownerName) throws CreateException { // use abstract methods to initialize the bean setAccountID(accountID); setOwnerName(ownerName); return new AccountPK(accountID); } // no finder methods… (container implements them) // // Business Logic Methods // /** * Deposits amt into account. */ public void deposit(double amt) throws AccountException { System.out.println("deposit(" + amt + ") called."); setBalance(getBalanace() + amt); } /** * Withdraws amt from bank account. * @throw AccountException thrown if amt > available balance */ public void withdraw(double amt) throws AccountException { System.out.println("withdraw(" + amt + ") called."); if (amt > getBalance()) { throw new AccountException("Your balance is " + getBalance() + "! You cannot withdraw " + amt + "!"); } setBalance(getBalance() – amt); } public abstract Collection ejbSelectAllAccountBalances() throws FinderException; /** * This home business method is independent of any * particular account instance. It returns the total * of all the bank accounts in the bank. */ public double ejbHomeGetTotalBankValue() throws Exception { // get a collection of bank account balances Collection c = this.ejbSelectAllAccountBalances(); // loop through the collection and return sum

© 2006, Watsh Rajneesh. All Rights Reserved.

47/86

2/9/2008

Iterator it = c.iterator(); double sumTot = 0.0; while(it.hasNext()) { sumTot += ((Double) it.next ()).doubleValue(); } return sumTot; } }

Deployment Descriptor
We need to inform the container about our entity bean, the container managed fields and the associated EJB QL for the finder and select methods. <?xml version="1.0" encoding="UTF-8"?> <ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee" version="2.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejbjar_2_1.xsd"> <display-name>Account</display-name> <enterprise-beans> <entity> <ejb-name>AccountBean</ejb-name> <home>examples.cmp.AccountHome</home> <remote>examples.cmp.Account</remote> <ejb-class>examples.cmp.AccountBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>examples.cmp.AccountPK</prim-key-class> <reentrant>false</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>ACCOUNTS</abstract-schema-name> <cmp-field> <field-name>accountID</field-name> <field-name>ownerName</field-name> <field-name>balance</field-name> </cmp-field> <primarykey-field>accountID</primarykey-field> <query> <query-method> <method-name>findByPrimaryKey</method-name> <method-params> <method-param>examples.cmp.AccountPK</method-param> </method-params> </query-method> <ejb-ql> SELECT OBJECT(a) FROM ACCOUNTS a WHERE a.accountID = ?1 </ejb-ql> </query> <query> <query-method> <method-name>findByOwnerName</method-name>

© 2006, Watsh Rajneesh. All Rights Reserved.

48/86

2/9/2008

<method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql> SELECT OBJECT(a) FROM ACCOUNTS a WHERE a.ownerName = ?1 </ejb-ql> </query> <query> <query-method> <method-name>selectAllAccountBalances</method-name> <method-params/> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(a) FROM ACCOUNTS a WHERE a.balance > 0]] </ejb-ql> </query> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>AccountBean</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <method> <ejb-name>AccountBean</ejb-name> <method-intf>Home</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar> [Note: ejbSelect does not work! Comment out in the bean code and the DD. Problem in EJB QL.] All EJB QL that contain < or > must be enclosed in CDATA sections (or else the XML parser will confuse a < or > as part of some xml tag and complain). Client (code in the BMP section of this document) used to test BMP, can be used to test CMP entity bean too without any modification. Note: Its always better to use a primary key class even when you have a single field as primary key. Wrapping that field in a primary key class aids in encapsulating the fields and write code in terms of the primary key class. So in future if the primary key class uses some other field then code which depends on the primary key class will still remain same.

Message Driven Bean
Messaging service (MOM – message-oriented middleware) receives messages from one or more message producers and broadcasts those messages to one or more message consumers. So producer can send message and then continue processing and can optionally be notified of the response later when the consumer finishes. Thus messaging aids in asynchronous programming.

© 2006, Watsh Rajneesh. All Rights Reserved.

49/86

2/9/2008

Pros of messaging paradigm are as follows: 1. Non blocking request processing: message producer does not need to block when executing a request. 2. Message delivery guarantee: MOM (message oriented middleware) supports guaranteed message delivery, you can send a message and know for sure that it will reach its destination, even if the consumer is not available. The MOM will route the message to the consumer once it is available. 3. Support for multiple producers and consumers. Cons of messaging are: 1. It can be slower due to overhead of having a middleman (the MOM service). Typical MOM are: Tibco Rendezvous, IBM Websphere MQ, BEA Tuxedo/Q, Sun Java System Messaging Server, Microsoft MSMQ, Sonic MQ, FioranoMQ. These products can give value-added services like guaranteed message delivery, fault tolerance, load balancing of destinations, subscriber throttling of message consumption, inactive subscribers, support for SOAP over JMS etc.

Java Messaging Service (JMS)
JMS is a standard like JDBC and JNDI, which has two parts: an API layer which you use to write code to send and receive messages, and a SPI where you plugin JMS providers for a particular product (which knows how to talk to a specific MOM implementation). So you can learn JMS API once and reuse your messaging code with different plug-and-play MOM implementations.

Messaging Domains

Pub/sub domain is an implementation of distributed event processing model. Subscribers register their interest in a particular event topic. Publishers (event sources) create messages (events) that are distributed to all of the subscribers. Publishers donot know who all are interested in the events. Point to point: you can have only a single consumer for each message. Multiple consumers can grab the message off the queue but any given message is consumed exactly once. Multiple producers can send messages to the queue.

© 2006, Watsh Rajneesh. All Rights Reserved.

50/86

2/9/2008

JMS Programming Model

Steps to use JMS API for sending/receiving message:
import javax.naming.*; import javax.jms.*; import java.util.*; public class Client { public static void main (String[] args) throws Exception { // Initialize JNDI Context ctx = new InitialContext(System.getProperties()); // 1: Lookup ConnectionFactory via JNDI TopicConnectionFactory factory = (TopicConnectionFactory) ctx.lookup(“TopicConnectionFactory”); // 2: Use ConnectionFactory to create JMS connection TopicConnection connection = factory.createTopicConnection(); // 3: Use Connection to create session TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); // 4: Lookup Destination (topic) via JNDI Topic topic = (Topic) ctx.lookup(“testtopic”); // 5: Create a Message Producer – associating the session with the topic TopicPublisher publisher = session.createPublisher(topic); // 6: Create a text message, and publish it TextMessage msg = session.createTextMessage(); msg.setText(“This is a test message.”); publisher.publish(msg);

}

}

© 2006, Watsh Rajneesh. All Rights Reserved.

51/86

2/9/2008

createTopicSession takes two params: false means we don’t want to use transactions and Session.AUTO_ACKNOWLEDGE means to auto acknowledge the receipt of a message. This is meant for receiver of the message. Since we are sending messages to the topic so we don’t really care about this param.

Message driven beans are message consumers. It was introduced in EJB 2.0. It can receive JMS messages as well as other types of messages (using pluggable message providers feature for receiving non JMS messages – this feature support was added in EJB 2.1 Spec). Message driven beans consume messages of a given message type in accordance with the message listener interface it employs, that is JMS-based message driven beans will implement javax.jms.MessageListener interface. As of EJB 2.1, Message driven beans can employ different listener interfaces to consume different message types in addition to JMS (like EIS specific messages). This is achieved with help from J2EE connector architecture 1.5. So you can provide resource adapters to asynchronously deliver messages to message endpoints (MDBs) residing in the app server independent of specific messaging type or semantics. So resource adapters can act as message providers. Resource adapters are pluggable to any J2EE compliant app server. For example, to receive EbXML messages in your enterprise application, we can write a EbXML resource adapter which provides a specific messaging listener interface (say, com.xyz.EbXMLMessageListener) which can be implemented by MDBs so as to receive EbXML messages. Thus, any enterprise application can send any type of messages to a MDB via J2EE connector architecture based resource adapter. A client cannot access a MDB through a component interface. They can only send messages to the MDB which it will receive and process. So, MDBs don’t have home, local home, remote or local interface. The resource adapter (via the container) calls the onMessage() (or similar method as defined by the specific message listener interface that MDB implements) upon arrival of a message. The javax.jms.MessageListener has onMessage() method which can accept a JMS message of types: 1. ByteMessage , 2. ObjectMessage, 3. TextMessage, 4. StreamMessage or 5. MapMessage.

© 2006, Watsh Rajneesh. All Rights Reserved.

52/86

2/9/2008

You can use instanceof operator to determine the exact type of a message at runtime. Listener method(s): 1. May not have a return value 2. Might not send back an exception to clients but can generate a system level exception due to a unchecked exception unhandled in the code and container will handle such exceptions. 3. Message driven beans are stateless. Thus multiple instances of MDB can process multiple messages from the JMS destination or resource adaptor consurrently.

Bean class
public interface javax.jms.MessageListener { public void onMessage(Message message); } public interface javax.ejb.MessageDrivenBean extends javax.ejb.EnterpriseBean { public void ejbRemove() throws EJBException; public void setMessageDrivenContext(MessageDrivenContext ctx) throws EJBException; }

Methods to be implemented in an MDB: 1. onMessage(message) – invoked for each message that is consumed by the bean. 2. ejbCreate() – there must be one and only one ejbCreate() method which does not take any argument. This is similar to stateless session beans as MDBs also donot have any client specific states that span messasges. 3. Bean class constructor – a default no arg constructor is a must. 4. ejbRemove() – use this method to clean up resources used by bean. 5. setMessageDrivenContext(MessageDrivenContext) –MDB can use the context to callback transaction related methods only (and not the getCallerPrincipal() etc methods as it does not have a client associated with it so no client security context to verify).

package examples; import javax.ejb.*; import javax.jms.*; /** * Sample JMS Message-Driven Bean */

© 2006, Watsh Rajneesh. All Rights Reserved.

53/86

2/9/2008

public class LogBean implements MessageDrivenBean, MessageListener { protected MessageDrivenContext ctx; /** * Associates this Bean instance with a particular context. */ public void setMessageDrivenContext(MessageDrivenContext ctx) { this.ctx = ctx; } /** * Initializes the bean */ public void ejbCreate() { System.err.println(“ejbCreate()”); } /** * Our one business method */ public void onMessage(Message msg) { if (msg instanceOf TextMessage) { TextMessage tm = (TextMessage) msg; try { String text = tm.getText(); System.err.println(“Received new message : “ + text); } catch(JMSException e) { e.printStackTrace(); } } } /** * Destroys the bean */ public void ejbRemove() { System.err.println(“ejbRemove()”); }

}

Note: A MDB can register with EJB timer service for time based notifications by implementing javax.ejb.TimedObject interface. Container will then invoke the bean’s ejbTimeout() method upon timer expiration. MDB class code is independent of destination type (queue or topic). The deployment descriptor determines whether a topic or a queue is consumed.

Client (Message Producer)
package examples; import javax.naming.*; import javax.jms.*; import java.util.*; public class LogBeanClient { public static void main (String[] args) throws Exception { Properties env = new Properties(); env.put("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory"); env.put("java.naming.provider.url", "iiop://localhost:3700"); InitialContext ctxt = new InitialContext(env); TopicConnectionFactory factory = (TopicConnectionFactory) ctxt.lookup("jms/TopicConnectionFactory");

© 2006, Watsh Rajneesh. All Rights Reserved.

54/86

2/9/2008

TopicConnection connection = factory.createTopicConnection(); TopicSession session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE); Topic topic = (Topic) ctxt.lookup("jms/Topic"); TopicPublisher publisher = session.createPublisher(topic); TextMessage msg = session.createTextMessage(); msg.setText("This is a test message."); publisher.publish(msg); System.out.println ("Message published to jms/Topic. Please check application” + “ server's console to see the response from MDB."); } }

Note: Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory"); env.put(Context.PROVIDER_URL, "localhost:1099"); Context initialContext = new InitialContext(env); Notice that the code does not use the property names such as java.naming. factory.initial, but instead uses Context.INITIAL_CONTEXT_FACTORY and Context.PROVIDER_URL. This is because the javax.naming.Context interface defines a set of constants for the names of the properties that you need to set. Thus, you do not have to remember strings such as java.naming.factory.initial. This also makes your code more flexible because it is independent of any changes that might be made to the property names in future versions of JNDI. You will see more on the different properties and their names shortly. Although it is possible to hard code the JNDI properties, it is the first two approaches that are the most suitable for production environments. For both, all that you need to do is distribute a text file with the application. When you create an InitialContext, JNDI searches for any application resource files called jndi.properties on the classpath. JNDI also looks in the Java runtime home directory (which is the jre subdirectory in the Java JDK home directory) for a file called lib\jndi.properties. All the properties that you define in these files are placed into the environment that belongs to the initial context. For example, the j2ee.jar file in the lib directory of the J2EE RI contains these lines:: java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory java.naming.factory.url.pkgs=com.sun.enterprise.naming These are a set of properties, which are simply name/value pairs. In practice, as long as the j2ee.jar file is on the classpath, you should be all set.The first of these two properties, java.naming.factory.initial, enables you to set the fully qualified class name of the Initial Context Factory for the JNDI Service Provider. That is, you use this property to specify which JNDI Service Provider you want to use. If you want to use the default naming service supplied with the J2EE RI (and the j2ee.jar file is not on your classpath), you would use the following line in your jndi.properties file: java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory Sun Microsystems provides several free reference implementations that are mentioned in the Table 14.1. You can specify the values from the table for the Context.INITIAL_CONTEXT_FACTORY environment property. Sun Microsystems maintains a list of service providers for JNDI on its Web site at http://java.sun.com/products/jndi/serviceproviders.html.

© 2006, Watsh Rajneesh. All Rights Reserved.

55/86

2/9/2008

Table 13.1 Values of Context.INITIAL_CONTEXT_FACTORY (java.naming.factory.initial) Value com.sun.jndi.cosnaming.CNCtxFactory com.sun.jndi.fscontext.RefFSContextFactory com.sun.jndi.dnc.DnsContextFactory com.sun.jndi.ldap.LdapCtxFactory Naming Service CORBA Naming Service (COS) File System DNS LDAP

com.sun.jndi.rmi.registry.RegistryContextFactory RMI Registry

You can find more information on these properties in the documentation for the javax.naming.Context and Sun's JNDI Tutorial (http://java.sun.com/products/jndi/tutorial/index.html).

Deployment Descriptor
<?xml version='1.0' encoding='UTF-8'?> <ejb-jar xmlns="http://java.sun.com/xml/ns/j2ee" version="2.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb -jar_2_1.xsd" > <display-name>LogEjb</display-name> <enterprise-beans> <message-driven> <ejb-name>LogBean</ejb-name> <ejb-class>examples.LogBean</ejb-class> <messaging-type>javax.jms.MessageListener</messaging-type> <transaction-type>Bean</transaction-type> <message-destination-type>javax.jms.Topic</message-destination-type> <message-destination-link>PhysicalTopic</message-destination-link> </message-driven> </enterprise-beans> <assembly-descriptor> <message-destination> <message-destination-name>PhysicalTopic</message-destination-name> </message-destination> </assembly-descriptor> </ejb-jar>

<message-destination-type>

Specifies whether the bean should consume queue or topic messages.

Since the names of actual topic and queue deployed into JMS server are application server specific, the mapping of a bean’s container to a specific JMS server destination needs to be done in the application server specific deployment descriptor. The following example illustrates the use of message destination linking in the deployment descriptor.
<enterprise­beans> <session> ... <ejb­name>EmployeeService</ejb­name> <ejb­class>com.wombat.empl.EmployeeServiceBean</ejb­class> ... <message­destination­ref> <message­destination­ref­name>

© 2006, Watsh Rajneesh. All Rights Reserved.

56/86

2/9/2008

jms/EmployeeReimbursements </message­destination­ref­name> <message­destination­type>javax.jms.Queue</message­destination­type> <message­destination­usage>Produces</message­destination­usage> <message­destination­link>ExpenseProcessingQueue</message­destination­link> </message­destination­ref> </session> ... <message­driven> <ejb­name>ExpenseProcessing</ejb­name> <ejb­class>com.wombat.empl.ExpenseProcessingBean</ejb­class> <messaging­type>javax.jms.MessageListener</messaging­type> ... <message­destination­type>javax.jms.Queue</message­destination­ type> <message­destination­link>ExpenseProcessingQueue</message­destination­ link> ... </message­driven> ... </enterprise­beans> ... <assembly­descriptor> ... <message­destination> <message­destination­name>ExpenseProcessingQueue</message­destination­ name> </message­destination> ... </assembly­descriptor> The Application Assembler uses the message­destination­link element to indicate that the message destination reference EmployeeReimbursement  declared in the EmployeeService  enterprise bean is linked to the ExpenseProcessing  message-driven bean by means of the commen destination ExpenseProcessingQueue.

Optionally, as of EJB 2.1, you can add <application-config-property> as sub-elements to <message-driven> tag where you can configure the MDBs operational information: <activation-config-property> Destination Type configuration for MDB (whether <activation-config-property-name> they consume messages from queue or topic) destinationType </activation-config-property-name> <activation-config-property-value> javax.jms.Topic </activation-config-property-value> </activation-config-property> <activation-config-property> Message Selector (used to filter messages sent to <activation-config-property-name> bean). They increase performance by reducing the messageSelector number of messages sent to MDBs. </activation-config-property-name> <activation-config-property-value> The message provider (client) must first set the JMSType=’log’ AND logLevel=’severe’ header on JMS message using JMS API as </activation-config-property-value> message.setStringProperty(“logLevel”, “severe”) </activation-config-property> before sending message to destination (a queue or topic). The container applies the message selector criteria before delivering message to a MDB. <activation-config-property> In case of CMT (container managed transaction) <activation-config-property-name> there is no need for acknowledgement as the acknowledgeMode container delivers the message to MDB in the </activation-config-property-name> context of a transaction, and if the transaction rolls <activation-config-property-value> back then the message is automatically put back on

© 2006, Watsh Rajneesh. All Rights Reserved.

57/86

2/9/2008

Auto-acknowledge </activation-config-property-value> </activation-config-property>

the queue. For BMT, the transaction occurs within MDB and begins and ends in the onMessage() method, in which case you need to tell the container to acknowledge the receipt of messages to the JMS server. You can either tell the container to immediately acknowledge the receipt of the message (Auto-acknowledge) in case of successful return from onMessage() but if some Runtime exception is thrown by your bean then the container will handle it and will put back the message on the queue. Or you can tell the container to take its own time (Dups-ok-acknowledge) to acknowledge the receipt of message to the JMS server (based on when the container finds computing time/resource to do so) in which case the container may not acknowledge the message fast enough and your MDB might receive the same message (duplicate) again. You should use this only if you can tolerate duplicate messages. Durability allows persistent messages to be sent to a topic on the JMS server. So if the application server hosting the MDB crashes then the message will be persisted on the JMS server topic until the MDB subscribed to the topic is active again and has acknowledged the consumption of all stored messages. MDB can register itself as durable or non-durable subscriber to messages published to a topic.

<activation-config-property> <activation-config-property-name> subscriptionDurability </activation-config-property-name> <activation-config-property-value> NonDurable </activation-config-property-value> </activation-config-property>

Define the app server specific ejb-jar file: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE sun-ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Application Server 8.0 EJB 2.1//EN " "http://www.sun.com/software/appserver/dtds/sun-ejb-jar_2_1-0.dtd"> <sun-ejb-jar> <enterprise-beans> <name>LogEjb</name> <ejb> <ejb-name>LogBean</ejb-name> <jndi-name>jms/Topic</jndi-name> <mdb-connection-factory> <jndi-name>jms/TopicConnectionFactory</jndi-name> </mdb-connection-factory> </ejb> <message-destination> <message-destination-name>PhysicalTopic</message-destination-name> <jndi-name>jms/Topic</jndi-name> </message-destination> </enterprise-beans> </sun-ejb-jar> You can use the deploy tool for the app server to create the JMS Resources : Connection resource as well as the Destination Resource. You will be asked to provide a JNDI name when you create these resources. In

© 2006, Watsh Rajneesh. All Rights Reserved.

58/86

2/9/2008

our case, they should be jms/TopicConnectionFactory (connection resource) and jms/Topic (destination resource). Deploy the EJB jar file for your bean. Run the client to publish the message on the Topic, and check the server log file where the bean will have printed out the message received.

The container that subscribes to a topic consumes any given message only once. So if five instances of MDB exist in the pool, only one of the instances will receive any particular message. Other instances can be used to concurrently process other messages published on the same topic. If same MDB is deployed to many containers in a cluster, then each deployment of the JMS MDB will consume a message from the topic it subscribes to. So the same message will be processed by an MDB instance residing in different containers in the cluster. If you want that each message is consumed only once in a cluster, then deploy a Queue instead of a Topic. For a Queue type destination, the JMS server will deliver any message on the queue to only one consumer (container). Each container registers as a consumer to the Queue and the JMS server load-balances messages to the consumers based on consumer’s availability. JMS MDBs that bind to Queues that are deployed in a cluster are ideal for scalable processing of messages. JMS server does not guarantee delivery of messages to a pool of JMS MDBs in any particular order. So MDBs should be prepared to process messages that are not in sequence. You can use Queues to partition business processing in a cluster as shown below:

© 2006, Watsh Rajneesh. All Rights Reserved.

59/86

2/9/2008

Thus two different queues can be used to partition the business processing in a cluster. The production queue will experience more load from real users so the cluster size for production stack systems can be scaled to accommodate more traffic. A poison message is a message that is continuously re-transmitted by a JMS destination to the consumer because the consumer continuously fails to acknowledge the consumption of the message. This can happen if in case of container managed transaction, the MDB calls messageDrivenContext.setRollbackOnly()/or throws some system level exception, every time forcing the transaction to be rolled back and the container will not send an acknowledgement in this case so the destination will resend the message to the consumer. To avoid this case, its best not to throw a system level exception (like EJBException) and MDB’s should not throw application level exception (its discouraged practice as application level exceptions are meant for clients and MDBs don’t have clients), so just log the error and return (thus ignoring the message which caused the error and continue to process next message). Remember, application level exceptions when thrown will not lead to a transaction roll back. If Bean managed transaction is used for MDB instead of container managed transaction, then the container does not have any transaction to rollback and thus the acknowledgement of message is always carried out. So use Bean Managed Transaction to avoid the possibility of poison messages. EJB spec does not define any mechansim that specifies how MDBs can propagate a response back to client that originally generated the message. Heres a strategy to employ when you want the client to receive the

© 2006, Watsh Rajneesh. All Rights Reserved.

60/86

2/9/2008

responses from MDBs (in a somewhat secure way guaranteeing fault tolerance, message filtering etc). For more alternatives refer page 249-253 of Mastering EJB 3rd Edn book.

Application properties can be set by setTextMessage() method on the client end using JMS API. Security can be improved by introducing a session EJB (stateless/stateful) as the topic that response messages are delived to can be made available only internally by simply not exposing it to direct client access. A fixed OutgoingResponseTopic is created at the JMS server where the responses are posted by the MDBs. Further application properties can be added to the outgoing message by the client (for eg. If the client sends out more than one request then it might also want to filter on the RequestID parameter with which it can associate an incoming response message with a request.)

EJB Environment & Best Practices
From within the container, when calling one bean from another bean, you can obtain the default JNDI initial context (ie you don’t need to pass a Context.INITIAL_CONTEXT_FACTORY and Context.PROVIDER_URL. These will values will be set to default for your container.) So you can say:
// Obtain the DEFAULT JNDI initial context by calling the // no-argument constructor Context ctx = new InitialContext(); // Look up the home interface Object result = ctx.lookup(“java:comp/env/ejb/CatalogHome”); // Convert the result to the proper type, RMI-IIOP style CatalogHome home = (CatalogHome) javax.rmi.PortableRemoteObject.narrow(result, CatalogHome.class); // Create a bean Catalog c = home.create(...);

java:comp/env/ejb context is the recommended context in which to put your bean names that are referrenced from other beans.

© 2006, Watsh Rajneesh. All Rights Reserved.

61/86

2/9/2008

EJB References
An EJB reference is a nickname for the JNDI location that you want to look up a bean. Your code then looks up a home reference via this nickname and the deployer then binds that nickname (ejb reference) to the JNDI location of its choice. For example,
... <enterprise-beans> <!-Here, we define our Catalog bean. Notice we use the “Catalog” ejb-name. We will use this below. --> <session> <ejb-name>Catalog</ejb-name> <home>examples.CatalogHome</home> ... </session> <session> <ejb-name>Pricer</ejb-name> <home>examples.PricerHome</home> ... <ejb-ref> <description> This EJB reference says that the Pricing Engine session bean (Pricer) uses the Catalog Engine session bean (Catalog) </description> <!-The nickname that Pricer uses to look up Catalog. We declare it so the deployer knows to bind the Catalog home in java:comp/env/ejb/CatalogHome. This may not correspond to the actual location to which the deployer binds the object via the container tools. The deployer may set up some kind of symbolic link to have the nickname point to the real JNDI location. --> <ejb-ref-name>ejb/CatalogHome</ejb-ref-name> <!-- Catalog is a Session bean --> <ejb-ref-type>Session</ejb-ref-type> <!-- The Catalog home interface class --> <home>examples.CatalogHome</home> <!-- The Catalog remote interface class --> <remote>examples.Catalog</remote> <!-- (Optional) the Catalog ejb-name --> <ejb-link>Catalog</ejb-link> </ejb-ref> </session> </enterprise-beans> ...

Similar to the message-destination-link we saw earlier where a JMS destination was being shared between two beans linking by the message-desitination-name. Similarly, when one bean has to lookup another bean’s home interface then it can link to the bean by the ejb-link tag using bean name (optionally) and has to specify the nickname with which it will be looking up the bean. The deployer will use the information in the DD under Pricer bean to bind the Catalog bean with the nickname (or use a JNDI symbolic link) in the JNDI tree. The Catalog bean could also reside in some other Ejb jar file than Pricer bean using its own DD. A bean can also access another bean using its Local interface in the same fashion. Only change the

© 2006, Watsh Rajneesh. All Rights Reserved.

62/86

2/9/2008

1. <ejb-ref> to <ejb-local-ref>,
2.

3.

<home> to <local-home> and <remote> to <local>.

The lookup code will change accordingly,
// Obtain the DEFAULT JNDI initial context by calling the // no-argument constructor Context ctx = new InitialContext(); // Look up the home interface Object result = ctx.lookup(“java:comp/env/ejb/CatalogLocalHome”); // Convert the result to the proper type. No RMI-IIOP cast // required since local interfaces are being used. CatalogLocalHome home = (CatalogLocalHome) result; // Create a bean CatalogLocal c = home.create(...);

Resource Factories
A resource factory is the driver that gives you connections (eg JDBC/JMS driver or JCA resource adapter). EJB mandates that you need to use JNDI to lookup a resource factory.
// Obtain the initial JNDI context Context initCtx = new InitialContext(); // Perform JNDI lookup to obtain resource factory javax.sql.DataSource ds = (javax.sql.DataSource) initCtx.lookup(“java:comp/env/jdbc/ejbPool”);

And in your DD:
... <enterprise-beans> <session> <ejb-name>Catalog</ejb-name> <home>examples.CatalogHome</home> ... <!-This element indicates a resource factory reference --> <resource-ref> <description> This is a reference to a JDBC driver used within the Catalog bean. </description> <!-The JNDI location that Catalog uses to look up the JDBC driver. We declare it so the deployer knows to bind the JDBC driver in java:comp/env/jdbc/ejbPool. --> <res-ref-name>jdbc/ejbPool</res-ref-name> <!-The resource factory class --> <res-type>javax.sql.DataSource</res-type> <!-Security for accessing the resource factory. Can either be “Container” or “Application”. --> <res-auth>Container</res-auth> <!-Whether connections should be shared with other clients in the different transactions -->

© 2006, Watsh Rajneesh. All Rights Reserved.

63/86

2/9/2008

<res-sharing-scope>Sharable</res-sharing-scope> </resource-ref> </session> </enterprise-beans> ...

Environment Properties
These are application specific properties that your beans read in at run time. Container reads in this DD and makes the environment properties available for your bean at runtime. These are put in java:comp/env context or in some subcontext of this context.
... <enterprise-beans> <session> <ejb-name>Pricer</ejb-name> <home>examples.PricerHome</home> ... <!-This element contains a single environment property. The property is only accessible from the Pricer. --> <env-entry> <description> The algorithm for this pricing engine. </description> <!-The JNDI location that Pricer uses to look up the environment property. We declare it so the container knows to bind the property in java:comp/env/PricerProperties/algorithm. --> <env-entry-name>Pricer/algorithm</env-entry-name> <!-- The type for this environment property --> <env-entry-type>java.lang.String</env-entry-type> <!-- The environment property value --> <env-entry-value>NoTaxes</env-entry-value> </env-entry> </session> </enterprise-beans> ...

Using the environment properties is as follows:
// 1: Acquire the initial context Context initCtx = new InitialContext(); // 2: Use the initial context to look up // the environment properties String taxAlgorithm = (String) initCtx.lookup(“java:comp/env/Pricer/algorithm”); // 3: Do what you want with the properties if (!taxAlgorithm.equals(“NoTaxes”)) { // add tax }

EJB Object Handles
EJB Object handle is a long-lived proxy for an EJB Object. It’s a persistent reference to an EJB object. The getHandle() method is available only for remote interfaces (not local ones). Handles are not guranteed to be portable across containers from different vendors nor across machines. So if you have some items in your shopping cart (viz implemented as a stateful session bean) and you happen to loose connection, you’d want your shopping cart state maintained when you reconnect. Here’s how you use it:

© 2006, Watsh Rajneesh. All Rights Reserved.

64/86

2/9/2008

// First, get the EJB object handle from the EJB object. javax.ejb.Handle myHandle = myEJBObject.getHandle(); // Next, serialize myHandle, and then save it in // permanent storage. ObjectOutputStream stream = ...; stream.writeObject(myHandle); // time passes... // When we want to use the EJB object again, // deserialize the EJB object handle ObjectInputStream stream = . . .; Handle myHandle = (Handle) stream.readObject(); // Convert the EJB object handle into an EJB object MyRemoteInterface myEJBObject = (MyRemoteInterface) javax.rmi.PortableRemoteObject.narrow(myHandle.getEJBObject(), MyRemoteInterface.class); // Resume calling methods again myEJBObject.callMethod();

Home Handles
Persistent references to Home Objects. They may be useful because you can acquire a reference to a home object, persist it, and then use it again later without knowledge of the home object’s JNDI location.
// First, get the EJB home handle from the home object. javax.ejb.HomeHandle homeHandle = myHomeObject.getHomeHandle(); // Next, serialize the home handle, and then save it in // permanent storage. ObjectOutputStream stream = ...; stream.writeObject(homeHandle); // time passes... // When we want to use the home object again, // deserialize the home handle ObjectInputStream stream = ...; javax.ejb.HomeHandle homeHandle = (HomeHandle) stream.readObject(); // Convert the home object handle into a home object MyHomeInterface myHomeObject = (MyHomeInterface) javax.rmi.PortableRemoteObject.narrow(homeHandle.getHomeObject(), MyHomeInterface.class); // Resume using the home object myHomeObject.create();

If distributed transactions are a must for your application then Spring + POJO will not work. But Spring framework does support EJB based development of application. They provide a lightweight framework for writing business tier (lightweight because they provide declarative local transaction for POJO without relying on the container.) StrutsEJB project (http://strutsejb.dev.java.net) provides base classes and patterns (mainly business delegate, service locator, DTO, and Session Façade) to build Struts web application that uses EJB in the business tier. Struts also provides tag libraries for generating device markups (WML, HDML, and XHTML) for small device support. Model Driven Development (MDD) : model typically represents entity in the problem domain. MDD tools like Compuware OptimalJ or AndoMDA MDD can generate core J2EE design patterns (with discretion

© 2006, Watsh Rajneesh. All Rights Reserved.

65/86

2/9/2008

from the architect) from model diagrams. IBM RDD (Rational Rapid Developer) donot support any specific standard for MDD but have their own paradigm. MDD suits better for new applications. Refer http://middlewareresearch.com/endeavors/031126MDDCOMP/endeavor.jsp. Extreme Programming (XP) is a software engineering discipline whose core practices revolve around an underlying assumption: Change in requirements and hence software design will inevitably occur during the course of software development. Original thinker of XP – Kent Beck. Core principles are: 1. Iterative development: development is given a certain target to meet per iteration (checkpoints or milestones). Features for the iteration are defined. 2. EJB subphase: development phase for designing, developing, building and deploying EJBs on development systems. 3. Testing subphase: build unit test clients. 4. User subphase: present work done to actual users who test the application using the acceptance test plan. Avoid adding new features in the middle of the iteration. 5. Continuous Integration: keeping various application components in sync with each other so that system is fully integrated most times. Builds should be made atleast once a day. Idea is not to defer integration until last moment. 6. Refactoring: process of continuously improving the design of existing code without affecting code behavior. Involves restructuring of code so as to remove redundant code, reduce coupling in code, introduce better naming conventions in the code, or organize the code more cohesively. For more, refer http://industriallogic.com/xp/refactoring/catalog.html. 7. Test-driven development: prime focus for XP. XP is lightweight compared to more formal design processes like Rational Unified Process (RUP) or now obsoleted waterfall model. Apache Cactus (http://jakarta.apache.org/cactus/) is an extension of Junit specifically catering to testing enterprise java applications. Using Cactus makes more sense when you bean clients are Servlets/JSP which also reside in the J2EE environment (which is usually the case) as it tests these clients as well apart from EJB. You get end-to-end framework for unit testing EJB applications with a web front end. Cactus allows for writing three types of test case classes based on the ServletTestCase, JspTestCase, and FilterTestCase classes also known as redirectors. Hence, your test case classes will extend any one of these, depending on which client model you use, and get a home reference to your EJB, create an instance, call the method on it, and assert the test results. Ant task <cactus>, provides ANT integration. Aspect-Oriented Programming (AOP): aspects are the core of AOP. Aspects are reusable services that are quintessentially crosscutting to your application (eg, services that provide user authentication, authorization, logging of access to system, and persistence of application data). Crosscutting concerns because developer cannot write robust applications without taking care of them. Hence AOP is a programming platform that facilitates the development of aspects to mitigate concerns so that aspects can be reused by all living objects within a given environment. EJB containers implement these crosscutting concerns and provide reusable aspects so that all the beans deployed within the container can offload these concerns on the container aspects. So EJB container is an Aspect Oriented Implementation. EJB programming model does not allow you to develop new aspects to take care of concerns that are not supported by EJB container. So J2EE is not a AOP platform even though EJB uses AOP techniques. In order to use AOP in EJB, you can use frameworks like Spring AOP, AspectJ or tools provided by App Server vendors. JBoss and Websphere provide AOP support. So until EJB spec allows for AOP as standard, you loose portability using AOP with custom vendor tools. POJOs are used to get around contraints imposed by EJB standard – like accessing filesystem or read/write static fields (you cannot use static fields in your EJBs). We might also end up reusing these POJOs outside the EJB container, for example, in a Web application or a Swing application. In this

© 2006, Watsh Rajneesh. All Rights Reserved.

66/86

2/9/2008

scenario, it might be better to write reusable aspects to address concerns relevant to your POJOs. For example, consider a POJO that reads and writes to a file. Here you might need to log the timestamp of the last updating of the file. In which case, you would create an aspect to address the logging concern. This way you can use the Logging aspect no matter whether your POJO is being used within an EJB container or within a Web container or in a vanilla Java Swing application. OOP does not work when behavior needs to be reused horizontally, owing to the behavior’s crosscutting nature. Now why would you need to reuse behavior horizontally? Because you do not want your business object, for example a ShoppingCart, to inherit the behavior pertaining to transactions, since these behaviors are unrelated; you do not want an apple to inherit grape-like qualities; rather you want to mix apples and grapes to prepare a margarita drink. This is where AOP comes into picture. AOP and OOP are not competing but complementary technologies. Consider, for example, an EJB server where crosscutting aspects are provided to your object-oriented beans. EJB programming APIs support only static invocation (where information about the interface and methods to invoke on its object are known at the compile time). Reflection facilitates dynamic (runtime) invocation of methods already implemented in class. Dynamic proxy approach allows dynamically implementing a proxy class that implements a list of interfaces specified by class at runtime. Proxy is generated dynamically and method invocation on the proxy object (for eg. java.lang.reflect.Proxy) is dispatched to a single method named invoke() which takes the method name and invokes it via java.lang.reflect.Method object and takes the method arguments as Object[]. Thus dynamic proxy object uses reflective mechanism and provides a generic object that is capable of intercepting methods from clients on behalf of any server object implementing the interfaces this dynamic proxy implements. You can use it to dynamically invoke methods on EJB when client does not have a priori knowledge of interfaces implemented by EJB. To automate deployment of your EJB applications on multiple application servers, you can use XDoclet framework. XDoclet is a powerful, attribute oriented code generation engine. Using XDoclet, a developer can generate practically anything – XML descriptors (DDs – both standard and server specific ones), source code and so on – by inserting attributes (metadata) within Javadoc for their source. Uses are: Generate code for Value classes, primary key classes, struts action form based on Entity EJB, and home and remote interfaces. Also integration of XDoclet with ANT through Ejbdoclet tasks makes it even more powerful framework for deployments.

Transactions
We must guarantee data integrity even when many users concurrently update the data. A transaction is a series of operations that appear to execute as one large, atomic operation. Databases also offer concurrency control with different levels of isolation. But concurrency control for an enterprise application is not only required at datasource level but at the application level where you might have several steps in a business logic being performed and you require them to be one atomic operation – and of these steps, accessing a datasource might just be one part but within your EJB the transaction service will guarantee that if any unchecked or remote exception is thrown then container will rollback the transaction in which case revert your bean state to the original state and in case you used CMP for your datasource access then it will even not commit the data change you made to the datasource. Thus effectively the state of bean(s) will be changed only on success of all steps constituting the business method (or a series of them if multiple beans are involved and the same transaction is in effect for those beans – it is possible to start a new transaction for a bean’s business method though in which case if the new transaction rolls back and the business method throws an unchecked exception to the calling bean’s business method then the original transaction will also be rolled back). Since beans are single threaded so concurrency control is provided by the container by default by executing other bean instance of same type (from the instance pool) in case of concurrent requests. The bean code does not have to code for concurrency control.

© 2006, Watsh Rajneesh. All Rights Reserved.

67/86

2/9/2008

Transaction Jargons
4. Transaction Object: A transactional object (or transactional component) is an application
component, such as a banking component, that is involved in a transaction.

5. Transaction Manager: A transaction manager is responsible for managing the 6. 7.
transactional operations of the transactional components. It manages the entire overhead of a transaction, running behind the scenes to coordinate things Resource: A resource is a persistent storage from which you read or write. A resource could be a database, a message queue, or other storage. Resource Manager: A resource manager manages a resource. An example of a resource manager is a driver for a relational database, object database, message queue, or other store. Resource managers are responsible for managing all state that is permanent. The most popular interface for resource managers is the X/Open XA resource manager interface. Most database drivers support this interface. Because X/Open XA is the de facto standard for resource managers, a deployment with heterogeneous XA resource managers from different vendors can interoperate.

Transactional Models
Flat Transactions: is a series of operations that are performed atomically as a single unit of work. Flat transactions can be chained too but if one of the subtransaction rolls back then it causes the outer transactions to rollback too. This is the behavior supported by EJB transaction service. Nested Transactions: Anested transaction enables you to embed atomic units of work within other units of work. The unit of work that is nested within another unit of work can roll back without forcing the entire transaction to roll back. Therefore the larger unit can attempt to retry the embedded unit of work. If the embedded unit can be made to succeed, the larger unit can succeed. If the embedded unit of work cannot be made to work, it will ultimately force the entire unit to fail. What’s special about nested transactions is that subtransactions can independently roll back without affecting higher transactions in the tree. That’s a very powerful idea, and it solves our famous tripplanning problem: If each individual booking is a nested transaction, we can roll back any one booking without canceling all our other reservations. But in the end, if the nested transaction cannot be committed, the entire transaction will fail. EJB spec does not mandate support for nested transactions though so all transactions are flat for EJBs. A container managed transaction is shown below:

© 2006, Watsh Rajneesh. All Rights Reserved.

68/86

2/9/2008

The bean’s business method executes in the transaction context controlled by the container (which delegates to the bean for executing the business method). So if there is any system level execption in the bean then the transaction is rolled back by the container. If a session bean’s transaction is already been initiated and in its business method the bean invokes a method on an entity bean then the entity bean can either leverage the same transactional context (Supports/Required transactional attribute) and execute within it or it can tell the container to start a new transactional context (RequiresNew) for its own use. You can even have a client-initiated transaction in which case a servlet/JSP tag library, application/applet or CORBA client or another enterprise bean which is client to your bean can being and end transactions in that client. Entity beans must use declarative or container managed transactions only as loading of data from the datasource and storing/updating the data in the datasource happen in two different methods (ejbLoad and ejbStore). When a business method of an entity bean is called then container first invokes the ejbLoad() to get the entity bean instance associated with data and once the business method completes, container will call the ejbStore() to sync up the database with the inmemory entity bean instance. So if we are doing programmatic transaction in an entity bean then we will have open the transaction in the ejbLoad() and close it in the ejbStore(). But since these methods are called by container so the bean has no say in what order or when the container calls these methods. So if one starts a transaction in ejbLoad then the transaction may not get a chance to complete if the container decides not to call the ejbStore after the business method (depends on the container algo – if it sees there isnt any change in the database data and the in-memory cache so it wont have anything to write back – in case where the business method called after ejbLoad errored out of did not change the state). So bean managed transaction is illegal for entity beans. Session and Message driven beans can have programmative (BMT) and CMT as their data access can happen within a single method boundary. A corollary of this discussion is that entity beans do not load and store their data on every method call; rather, they load and store their data on every transaction. If your entity beans are not performing well,

© 2006, Watsh Rajneesh. All Rights Reserved.

69/86

2/9/2008

it could be because a transaction is happening on each method call, and thus a database read/write is happening on every get/set method. The solution is to make sure your transactions begin earlier and end later, perhaps encompassing many entity bean method calls. By properly controlling the duration of your transactions with transaction attributes, you can control when database reads and writes happen with entity beans.

Transaction Attributes
A transaction attribute is a setting that you give to a bean to control how your bean is enlisted in containermanaged transactions. The transactional attribute is a required part of each bean’s deployment descriptor. The container knows how transactions should be handled with a bean by reading that bean’s transaction attribute from its deployment descriptor. Note that you can specify transaction attributes for entire beans or for individual bean methods. If both are specified, then method-level attributes take precedence.
<assembly-descriptor> <!-This demonstrates setting a transaction attribute on every method on the bean class. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>*</method-name> </method> <!-Transaction attribute. Can be “NotSupported”, “Supports”, “Required”, “RequiresNew”, “Mandatory”, or “Never”. --> <trans-attribute>Required</trans-attribute> </container-transaction> <!-You can also set transaction attributes on individual methods. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>setName</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> <!-You can even set different transaction attributes on methods with the same name that take different parameters. --> <container-transaction> <method> <ejb-name>Employee</ejb-name> <method-name>setName</method-name> <method-param>String</method-param> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor>

You must specify transaction attributes on all business methods for your beans. Furthermore, with entity beans you must specify transaction attributes that cover home interface methods, because the home interface creation methods insert database data and thus need to be transactional. JCA and Transactions The J2EE Connector Architecture defines a standard contract between Resource Adapters (RA) and application servers such that RA can leverage the container services for supporting transactions. This standard contract enables an application server to provide the infrastructure and runtime environment for

© 2006, Watsh Rajneesh. All Rights Reserved.

70/86

2/9/2008

transaction management of RA components. RA can support either a local transaction, which is managed internally by the resource manager, or it can support a distributed transaction, whose coordination does involve external transaction managers. If RA that supports local transactions, the client component, such as an EJB, will have to acquire the common client interface API object, such as javax.resource.cci.LocalTransaction or an equivalent from the resource adapter to demarcate the transactions. If RA supports distributed transactions, the container will automatically enlist the client in the transaction context, if the client wants to work within a distributed transaction. J2EE Connector Architecture 1.5 supports the inflow of transactions fromEnterprise Information System (EIS) to the J2EE environment. This is a powerful addition because it enables the J2EE applications to participate in transactions initiated by backend EIS. For example, you can make your stateless session bean participate in a transaction that was initiated in the Tuxedo environment, given that the underlying RA supports this contract.

Required
You should use the Required mode if you want your bean to always run in a transaction. If a transaction is already running, your bean joins in on that transaction. If no transaction is running, the EJB container starts one for you. The customer wants to use the credit card component to charge a user’s credit card when a user purchases a product from a Web site. The customer then wants to submit an order to manufacture that product, which is handled by a separate component. Thus, the customer has two separate components running but both of them run under the same transaction. If the credit card cannot be charged, the customer doesn’t want the order to be submitted. If the order cannot be submitted, the customer doesn’t want the credit card charged. Therefore the customer produces his or her own workflow bean, which first calls our credit card–charging bean and then calls the bean to generate a manufacturing order. The workflow bean is deployed with Required, so a transaction automatically starts up. Because your credit card bean is also deployed with Required, you join that transaction, rather than start your own transaction. If the order submission component is also deployed with Required, it joins the transaction as well. The container commits or aborts the transaction when the workflow bean is done.

RequiresNew
You should use the RequiresNew attribute if you always want a new transaction to begin when your bean is called. If a transaction is already under way when your bean is called, that transaction is suspended during the bean invocation. The container then launches a new transaction and delegates the call to the bean. The bean performs its operations and eventually completes. The container then commits or aborts the transaction and finally resumes the old transaction. RequiresNew is useful if your bean needs the ACID properties of transactions but wants to run as a single unit of work without allowing other external logic to also run in the transaction.

Supports
When a bean is called with Supports, it runs in a transaction only if the client had one running already. If the client does not have a transaction, the bean runs with no transaction at all. Because Supports will sometimes not run within a transaction, you should be careful when using this attribute. Missioncritical operations should be encapsulated with a stricter transaction attribute (like Required).

Mandatory
Mandatory mandates that a transaction must be already running when your bean method is called. If a transaction isn’t running, the javax.ejb.TransactionRequiredException exception is thrown back to the caller (or javax.ejb.Tranasction- RequiredLocalException if the client is local). Mandatory is useful if your component is designed to run within a larger system, such as a workflow system, where your bean is only part of a larger suite of operations, and you want to mandate that the larger operations start a transaction before calling your bean.

© 2006, Watsh Rajneesh. All Rights Reserved.

71/86

2/9/2008

NotSupported
If you set your bean to use NotSupported, then your bean cannot be involved in a transaction at all. For example, assume we have two enterprise beans, Aand B. Let’s assume bean A begins a transaction and then calls bean B. If bean B is using the NotSupported attribute, the transaction that A started is suspended. None of B’s operations are transactional, such as reads/writes to databases. When B completes, A’s transaction is resumed. You should use NotSupported if you are certain that your bean operations do not need the ACID properties. This should be used only if your beans are performing non–mission-critical operations, where you are not worried about isolating your bean’s operations from other concurrent operations. An example here is an enterprise bean that performs rough reporting. If you have an e-commerce Web site, you might write a bean that routinely reports a rough average number of e-commerce purchases per hour by scanning a database. Because this is a low-priority operation and you don’t need exact figures, NotSupported is an ideal, low-overhead mode to use.

Never
The Never transaction attribute means that your bean cannot be involved in a transaction. Furthermore, if the client calls your bean in a transaction, the container throws an exception back to the client (java.rmi.RemoteException if remote, javax.ejb.EJBException if local). This transaction attribute is useful when you want to make sure all clients that call your bean do not use transactions. This can help reduce errors in client code, because a client will not be able to call your bean erroneously in a transaction and expect your bean to participate in the ACID properties with other transaction participants.

© 2006, Watsh Rajneesh. All Rights Reserved.

72/86

2/9/2008

For example, let’s say you want to perform a transfer between two bank accounts. To achieve this, you might have a bank teller session bean that calls into two bank account entity beans. If you deploy all three of these beans with the Required transaction attribute, they will all be involved in a single transaction. Entity beans and stateful session beans with SessionSynchronization must use transactions. The reason is that both of these types of beans are inherently transactional in nature. Entity beans perform database updates, and stateful session beans with SessionSynchronization (which we describe later in this chapter) are also transactional. Therefore you normally can’t use the following attributes: Never, NotSupported, Supports. There is no client, and therefore transaction attributes that deal with the notion of a client’s transaction make no sense for message-driven beans—namely Never, Supports, RequiresNew, and Mandatory. Transactional Attributes Stateless Beans Session Stateful Session Beans implementing Session Synchronization Yes Yes Yes No No No Entity Beans Message Beans Driven

Required RequiresNew Mandatory Supports NotSupported Never

Yes Yes Yes Yes Yes Yes

Yes Yes Yes No No No

Yes No No No Yes No

Java Transaction API (JTA)
You can use the JTA in your client and bean code to programmatically control transactional boundaries. You can do very useful things with the JTA, such as start a transaction inside your bean, call other beans that also are involved in a transaction, and control whether things commit or abort. Non-EJB applications can use the JTA as well—the client code that calls your beans can use the JTA to control transaction boundaries in a workflow scenario, where the client code is calling multiple beans and wants each bean to participate in one transaction.

javax.transaction.UserTransaction
public interface javax.transaction.UserTransaction { public void begin(); -- begin a new transaction public void commit(); -- runs two-phase commit protocol on an existing transaction associated with current thread. Each resource manager makes its update durable. public int getStatus(); -- retrieves status of transaction associated with current thread. public void rollback(); -- rollbacks the transaction associated with current thread. public void setRollbackOnly(); -- force current transaction to rollback. public void setTransactionTimeout(int); -- max. time that a transaction can run before its rolled back. }

JTA also defines a number of constants that indicate the current status of a transaction.

public interface javax.transaction.Status { public static final int STATUS_ACTIVE; public static final int STATUS_NO_TRANSACTION; public static final int STATUS_MARKED_ROLLBACK; -- in case some party called setRollbackOnly(). public static final int STATUS_PREPARING; -- Phase one of two phase commit protocol. public static final int STATUS_PREPARED; -- Phase one completed. public static final int STATUS_COMMITTING; -- Phase two happening. public static final int STATUS_COMMITTED; -- Phase two completed. public static final int STATUS_ROLLING_BACK; public static final int STATUS_ROLLEDBACK; public static final int STATUS_UNKNOWN;

© 2006, Watsh Rajneesh. All Rights Reserved.

73/86

2/9/2008

}

Example bean method carrying out bean managed transaction:
/** * Deposits amt into account. */ public void deposit(double amt) throws AccountException { javax.transaction.UserTransaction userTran = null; try { System.out.println(“deposit(“ + amt + “) called.”); userTran = ctx.getUserTransaction(); userTran.begin(); balance += amt; userTran.commit(); } catch (Exception e) { if (userTran != null) userTran.rollback(); throw new AccountException(“Deposit failed because of “ + e.toString()); } }

A bean using the above method, must be deployed with transaction type of Bean. When using programmatic transaction always try to complete your transactions in the same method in which you began them.

setRollbackOnly
If your bean is participating in a transaction started by some other bean then you can doom a transaction (Ie force a transaction to abort) by calling setRollbackOnly() on your EJB context object. If your transaction participant is a POJO (and not an EJB component) then you will have to lookup the UserTransaction object in the JNDI and call its setRollbackOnly(), as shown below:
try { /* * 1: Set environment up. You must set the JNDI Initial * Context factory, the Provider URL, and any login * names or passwords necessary to access JNDI. See * your application server product’s documentation for * details on their particular JNDI settings. */ java.util.Properties env = ... /* * 2: Get the JNDI initial context */ Context ctx = new InitialContext(env); /* * 3: Look up the JTA UserTransaction interface * via JNDI. The container is required to * make the JTA available at the location * java:comp/UserTransaction. */ userTran = (javax.transaction.UserTransaction) ctx.lookup(“java:comp/UserTransaction”); /* * 4: Execute the transaction */ userTran.begin(); // perform business operations userTran.commit();

} catch (Exception e) { // deal with any exceptions, including ones // indicating an abort. }

© 2006, Watsh Rajneesh. All Rights Reserved.

74/86

2/9/2008

In case there are say 10 beans in a chain executing the same transaction, and bean 2 decides to doom the transaction then other beans should be able to detect that the transaction has been doomed and avoid performing work when a doomed transaction exists: 1. Container managed transactional beans can detect doomed transactions by calling getRollbackOnly() on their EJB Context object. If it returns true, then transaction is doomed. 2. Other participants, such as bean managed transactional beans, can get hold of UserTransaction object from the JNDI and call its getStatus() method.

Transaction Isolation

Dirty Read
Adirty read occurs when your application reads data from a database that has not been committed to permanent storage yet. Dirty reads can occur if you use the weakest isolation level, called READ UNCOMMITTED. With this isolation level, if your transaction is executing concurrently with another transaction, and the other transaction writes some data to the database without committing, your transaction will read that data in. The advantage of this isolation level is performance. The underlying transaction system doesn’t have to acquire any locks on shared data in this mode.Your code will read committed data only when running in READ COMMITTED mode. When you execute with this isolation level, you will not read data that has been written but is uncommitted. This isolation level thus solves the dirty read problem. One great use for this mode is for programs that read data from a database to report values of the data. Because reporting tools aren’t in general missioncritical, taking a snapshot of committed data in a database makes sense. READ COMMITTED is the default isolation level for most databases, such as Oracle or Microsoft SQL Server.

Unrepeatable Read
Unrepeatable reads occur when a component reads some data from a database, but upon rereading the data, the data has been changed. This can arise when another concurrently executing transaction modifies the data being read. REPEATABLE READ guarantees yet another property on top of READ COMMITTED: Whenever you read committed data from a database, you will be able to reread the same data again at a later time, and the data will have the same values as the first time. Hence, your database reads are repeatable. Use REPEATABLE READ when you need to update one or more data elements in a resource, such as one or more records in a relational database. You want to read each of the rows that you’re modifying and then be able to update each row, knowing that none of the rows are being modified by other concurrent transactions. If you choose to reread any of the rows at any time later in the transaction, you’d be guaranteed that the rows still have the same data that they did at the beginning of the transaction.

Phantom Read
A phantom is a new set of data that magically appears in a database between two read operations. For example, if your transaction reads a relational record, and a concurrent transaction commits a new record to the database, a new phantom record appears that wasn’t there before. You can easily avoid phantoms (as well as the other problems described earlier) by using the strictest isolation level: SERIALIZABLE. SERIALIZABLE guarantees that transactions execute serially with respect to each other, and it enforces the isolation ACID property to its fullest. This means that each transaction truly appears to be independent of the others. Use SERIALIZABLE for mission-critical systems that absolutely must have perfect transactional isolation. You are guaranteed that no data will be read that has been uncommitted. You’ll be able to reread the same data again and again. And mysterious committed data will not show up in your database while you’re operating due to concurrent transactions. Note:

© 2006, Watsh Rajneesh. All Rights Reserved.

75/86

2/9/2008

If your bean is managing transactions, you specify isolation levels with your resource manager API (such as JDBC). For example, you could call java.sql.Connection.SetTransactionIsolation(). If your container is managing transactions, there is no way to specify isolation levels in the deployment descriptor. You need to either use resource manager APIs (such as JDBC) or rely on your container’s tools or database’s tools to specify isolation. Unfortunately, there is no way to specify isolation for container-managed transactional beans in a portable way—you are reliant on container and database tools. This means if you have written an application, you cannot ship that application with built-in isolation. The best strategy is to develop EJBs that are as tolerant of isolation differences as possible. This is the typical technique used by many optimistic concurrency libraries that have been layered over JDBC and ODBC.

Durability and Two phase commit protocol
To support durability, transactions happen in two phases: 1. Phase 1: begins by sending a before commit message to all resources involved in the transaction. At this time, the resources involved in a transaction have a final chance to abort the transaction. If any resource involved decides to abort, the entire transaction is cancelled and no resource updates are performed. Otherwise, the transaction proceeds on course and cannot be stopped, unless a catastrophic failure occurs. To prevent catastrophic failures, all resource updates are written to a transactional log or journal. This journal is persistent, so it survives crashes and can be consulted after a crash to reapply all resource updates. 2. Phase 2: occurs only if Phase One completed without an abort. At this time, all of the resource managers, which can all be located and controlled separately, perform the actual data updates. In the distributed two-phase commit, there is one master transaction manager called the distributed transaction coordinator. The transaction coordinator runs the show and coordinates operations among the other transaction managers across the network.

A distributed two-phase commit transaction complicates matters, because the transaction managers must all agree on a standard mechanism of communicating. The communication mechanism used is called the transactional communications protocol. The most important piece of information sent over the

© 2006, Watsh Rajneesh. All Rights Reserved.

76/86

2/9/2008

transactional communications protocol is the transaction context. Atransaction context is an object that holds information about the system’s current transactional state. It is passed around among parties involved in transactions. By querying the transaction context, you can gain insight into whether you’re in a transaction, what stage of a transaction you are at, and other useful data. For any component to be involved in a transaction, the current thread in which the component is executing must have a transaction context associated with it. For a stateless session bean, aborting a business process is a simple task—simply throw an exception back to the client. But for a stateful session bean, things are a bit trickier. Stateful session beans represent business processes that span multiple method calls and hence have in-memory conversational state. Tossing away that conversation and throwing an exception to the client could entail a significant amount of lost work. Fortunately, a well-designed stateful session bean can salvage its conversations in the case of failed transactions. The key is to design your beans to be aware of changes to conversational state and to be smart enough to undo any of those changes if a transactional abort occurs. Your application server can aid you in determining when a transaction failed, enabling you to take application-specific steps. If your session bean needs to be alerted to transaction status (like failed transactions), your enterprise bean class can implement an optional interface called javax.ejb.SessionSynchronization.
public interface javax.ejb.SessionSynchronization { public void afterBegin(); public void beforeCompletion(); public void afterCompletion(boolean); }

The key method that is most important for rolling back conversations is afterCompletion(). The container calls your afterCompletion() method when a transaction completes either in a commit or an abort. You can figure out whether a commit or an abort happened by the Boolean parameter that gets passed to you in afterCompletion(): True indicates a successful commit, false indicates an abort. If an abort happened, you should roll back your conversational state to preserve your session bean’s conversation.
public class CountBean implements SessionBean, SessionSynchronization { public int val; public int oldVal; public void ejbCreate(int val) { this.val=val; this.oldVal=val; } public void afterBegin() { oldVal = val;} // save the state public void beforeCompletion() { } public void afterCompletion(boolean b) { if (b == false) val = oldVal; // if transaction failed, the rollback your converstation state. } public int count() { return ++val; } public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { } public void setSessionContext(SessionContext ctx) { }

}

Note: You can use SessionSynchronization only with Stateful Session Beans using container managed transactions.

Security
[Covered in my JBoss notes.]

© 2006, Watsh Rajneesh. All Rights Reserved.

77/86

2/9/2008

EJB Timer Service Relationship between Entity Beans
BMP entity beans manage relationships explicitly in the bean itself.
public class OrderBean implements EntityBean { // private fields // get/set methods // code to manage relationships in ejbXXX methods }

With CMP, you declare the way you would like your relationships to work in your deployment descriptor. The container then generates all the relationship code you need when the container subclasses your entity bean.
<ejb-jar> <enterprise-beans> ... define enterprise beans ... </enterprise-beans> <relationships> ... define EJB relationships ... </relationships> </ejb-jar>

Cardinality

The following code shows how to implement a one-to-one relationship using BMP:
public class OrderBean implements EntityBean { private String orderPK; private String orderName; private Shipment shipment; // EJB local object stub public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s;} ... public void ejbLoad() { // 1: SQL SELECT Order. This also retrieves the // shipment foreign key. // // 2: JNDI lookup of ShipmentHome // // 3: Call ShipmentHome.findByPrimaryKey(), passing // in the shipment foreign key } public void ejbStore() { // 1: Call shipment.getPrimaryKey() to retrieve // the Shipment foreign key // // 2: SQL UPDATE Order. This also stores the // Shipment foreign key. } }

© 2006, Watsh Rajneesh. All Rights Reserved.

78/86

2/9/2008

Our ejbLoad() method loads the database data of the order, and part of that data is a foreign key to the shipment. We need to transform that foreign key into a stub to a shipment bean. Therefore we need to perform a JNDI lookup of the shipment home and then call a finder method, passing in the foreign key. This gives us a stub, and we can then call business methods on the shipment. Our ejbStore() method stores the database data for the order, and part of that data is a foreign key to the shipment. We need to transform the shipment stub into a foreign key. Therefore, we need to call getPrimaryKey() on the shipment stub. This gives us our foreign key, and we can then perform the SQL. The following code shows how to implement that same one-to-one relationship using CMP:
public abstract class OrderBean implements EntityBean { // no fields public abstract Shipment getShipment(); public abstract void setShipment(Shipment s); ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty }

We do need to specify the relationship in the deployment descriptor, and we do so as follows:
<ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <enterprise-beans> ... </enterprise-beans> <relationships> <!-- This declares a relationship --> <ejb-relation> <!-- The nickname we’re giving this relationship --> <ejb-relation-name>Order-Shipment</ejb-relation-name> <!-This declares the 1st half of the relationship (the Order side) --> <ejb-relationship-role> <!-- The nickname we’re giving this half of the relationship --> <ejb-relationship-role-name> order-spawns-shipment </ejb-relationship-role-name> <!-- The Cardinality of this half of the relationship --> <multiplicity>One</multiplicity> <!-The name of the bean corresponding to this half of the relationship --> <relationship-role-source> <ejb-name>Order</ejb-name> </relationship-role-source> <!-Recall that a CMP entity bean has an abstract get/set method for the relationship. We need to tell the container which get/set method corresponds to this relationship, so that the container can generate the appropriate scaffolding code when sub-classing our bean. That is the purpose of this element, which is called the container-managed relationship (CMR) field. The value of the CMR field should be the name of your get/set method, but without the get/set, and with a slight change in capitalization. getShipment() becomes shipment. --> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmrfield> </ejb-relationship-role> <!-This declares the 2nd half of the relationship (the Shipment side)

© 2006, Watsh Rajneesh. All Rights Reserved.

79/86

2/9/2008

--> <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Shipment</ejb-name> </relationship-role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

The following code shows how to implement a one-to-many relationship using BMP:
public class CompanyBean implements EntityBean { private String companyPK; private String companyName; private Vector employees; // EJB object stubs public Collection getEmployees() { return employees; } public void setEmployees(Collection e) { this.employees = (Vector) e; } ... public void ejbLoad() { // 1: SQL SELECT Company // 2: JNDI lookup of EmployeeHome // 3: Call EmployeeHome.findByCompany(companyPK) } public void ejbStore() { // 2: SQL UPDATE Company }

}

A one-to-many relationship has a Vector of stubs, rather than a single stub. Our get/set method gets and sets this Vector (a Vector is a Collection). Our ejbLoad() method is responsible for loading the company state, as well as loading the relationships to employees. We do so by calling a finder method on the employee local home object. That finder method locates each employee that is a member of this company and returns a collection of stubs to us. Note that this causes a second SQL statement to be executed. The employee (not the company) has an ejbStore() that persists foreign keys to the company. The following code shows how to implement a one-to-many relationship using CMP:
public abstract class CompanyBean implements EntityBean { // no fields public abstract Collection getEmployees(); public abstract void setEmployees(Collection employees); ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty }

© 2006, Watsh Rajneesh. All Rights Reserved.

80/86

2/9/2008

<ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <enterprise-beans> ... </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Company-Employees</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Company-Employs-Employees </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Company</ejb-name> </relationship-role-source> <!-When you have a relationship with more than one object, you can use either a java.util.Collection or a java.util.Set. We need to identify which one we’re using. How do you choose between a Collection and a Set? A Collection can contain duplicates, whereas a Set cannot. This needs to match up to your bean’s get/set methods. --> <cmr-field> <cmr-field-name>employees</cmr-field-name> <cmr-field-type>java.util.Collection</cmr-field-type> </cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Employees-WorkAt-Company </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>Employee</ejb-name> </relationship-role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

To load a one-to-many relationship with BMP, we need to perform two SQL statements: We need to ejbLoad( ) the “1” side of the relationship and then find( ) the “N” side of the relationship. This is an inherent downside to BMP; you are limited to performing SQL operations at the granularity of an entity bean. With CMP, if your container is good, you can optimize and tell the container to perform one gigantic SQL statement to load yourself and your relationships.

© 2006, Watsh Rajneesh. All Rights Reserved.

81/86

2/9/2008

The following code shows how to implement a many-to-many relationship as two one-to-many relationships using BMP:
public class StudentBean implements EntityBean { private String studentPK; private String studentName; ... public void ejbLoad() { // SQL SELECT Student } public void ejbStore() { // SQL UPDATE Student } } public class CourseBean implements EntityBean { private String coursePK; private String courseName; ... public void ejbLoad() { // SQL SELECT Course } public void ejbStore() { // SQL UPDATE Course } } public class EnrollmentBean implements EntityBean { private String enrollmentPK; private Student student; // EJB local object stub private Course course; // EJB local object stub public Course getCourse() { return course; } public void setCourse(Course c) { this.course = c;} public Student getStudent() { return student; } public void setStudent(Student s) { this.student = s; } ... public void ejbLoad() { // 1: SQL SELECT Enrollment. This loads both the // Enrollment plus the foreign keys to Student // and Course. // // 2: JNDI lookup of StudentHome, CourseHome // // 3: Call findByPrimaryKey() on both the Student // and Course homes, passing the foreign keys } public void ejbStore() { // 1: Call getPrimaryKey() on Student,Course. This // gives us our foreign keys. // // 2: SQL UPDATE Enrollment } }

A brand-new entity bean, called enrollment, models the relationship between student and course. The enrollment bean keeps a stub for a course and a stub for a student and has get/set methods for clients to

© 2006, Watsh Rajneesh. All Rights Reserved.

82/86

2/9/2008

access those stubs. At the point in which object/relational mapping occurs, we transform those stubs to and from their foreign key database representation. The following code shows how to implement a fake many-to-many relationship using CMP:
public abstract class StudentBean implements EntityBean { // no fields ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty } public abstract class CourseBean implements EntityBean { // no fields ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty } public abstract class EnrollmentBean implements EntityBean { // no fields public abstract Course getCourse(); public abstract void setCourse(Course c); public abstract Student getStudent(); public abstract void setStudent(Student s); ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty } <ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <enterprise-beans> ... </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Enrollment-Student</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Enrollments-AreRegisteredBy-Student </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>Enrollment</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>student</cmr-field-name></cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Student-Has-Enrollments </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Student</ejb-name> </relationship-role-source> </ejb-relationship-role> </ejb-relation> <ejb-relation> <ejb-relation-name>Enrollment-Course</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> Enrollments-AreRegistrationsFor-Course </ejb-relationship-role-name> <multiplicity>Many</multiplicity> <relationship-role-source> <ejb-name>Enrollment</ejb-name>

© 2006, Watsh Rajneesh. All Rights Reserved.

83/86

2/9/2008

</relationship-role-source> <cmr-field><cmr-field-name>course</cmr-field-name></cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> Course-Has-Enrollments </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Course</ejb-name> </relationship-role-source> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

We model our fake many-to-many relationship as two many-to-one relationships (one for each bean in the relationship).

Directionality
The directionality of a relationship specifies the direction in which you can navigate a relationship. It can be Bi-directional or Uni-directional. In a bidirectional relationship, each bean in the relationship has a field pointing to the other bean, along with a get/set method. Birdirectional BMP:
public class OrderBean implements EntityBean { private String orderPK; private String orderName; // EJB local object stub, must be stored/loaded private Shipment shipment; public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s; } ... } public class ShipmentBean implements EntityBean { private String shipmentPK; private String shipmentName; // EJB local object stub, must be stored/loaded private Order order; public Order getOrder() { return order; } public void setOrder(Order o) { this.order = o; } ... }

Unidirectional BMP:
public class OrderBean implements EntityBean { private String orderPK; private String orderName; // EJB local object stub, must be stored/loaded private Shipment shipment; public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s; } ... } public class ShipmentBean implements EntityBean { private String shipmentPK; private String shipmentName; // No Order stub, no Order get/set method ... }

Birdirectional CMP:
public abstract class OrderBean implements EntityBean { // no fields public abstract Shipment getShipment(); public abstract void setShipment(Shipment s);

© 2006, Watsh Rajneesh. All Rights Reserved.

84/86

2/9/2008

}

... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty

public abstract class ShipmentBean implements EntityBean { // no fields public abstract Order getOrder(); public abstract void setOrder(Order o); ... public void ejbLoad() { } // Empty public void ejbStore() { } // Empty }

Each bean in the relationship has a pair of abstract get/set methods pointing to the other bean. We need to tell the container that these get/set methods are special relationship methods so that the container can generate relationship code.
<ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <enterprise-beans> ... </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Order-Shipment</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> order-spawns-shipment </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Order</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>shipment</cmr-fieldname></cmr-field> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Shipment</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>order</cmr-field-name></cmrfield> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

In the deployment descriptor, we set up two container-managed relationship (CMR) fields: one for each bean’s abstract get/set method pair that points to the other bean.

Aggregation vs Composition and Cascading Deletes
An aggregation relationship is a uses relationship. For example, students use courses. If you delete a student, you don’t delete the courses the student is registered in, because other students are using that course. Similarly, if you delete a course, you don’t murder a student! A composition relationship is an is-assembled-of relationship. For example, orders are assembled of line items. Deleting an order deletes all line items. Line items shouldn’t be around if their parent order is gone.

© 2006, Watsh Rajneesh. All Rights Reserved.

85/86

2/9/2008

An aggregation relationship does not cause a cascading delete, whereas a composition relationship does. With BMP, you implement a cascading delete manually in your ejbRemove() method.
public class OrderBean implements EntityBean { private String orderPK; private String orderName; private Shipment shipment; // EJB local object stub public Shipment getShipment() { return shipment; } public void setShipment(Shipment s) { this.shipment = s;} ... public void ejbRemove() { // 1: SQL DELETE Order // 2: shipment.remove(); }

}

With CMP, the container generates cascading delete code for you. If you have a composition relationship, you just need to set up a <cascade-delete/> tag in the deployment descriptor, as follows:
<ejb-jar xmlns=”http://java.sun.com/xml/ns/j2ee” version=”2.1” xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd”> <enterprise-beans> ... </enterprise-beans> <relationships> <ejb-relation> <ejb-relation-name>Order-Shipment</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name> order-spawns-shipment </ejb-relationship-role-name> <multiplicity>One</multiplicity> <relationship-role-source> <ejb-name>Order</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>shipment</cmr-field-name></cmrfield> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name> shipment-fulfills-order </ejb-relationship-role-name> <multiplicity>One</multiplicity> <cascade-delete/> <relationship-role-source> <ejb-name>Shipment</ejb-name> </relationship-role-source> <cmr-field><cmr-field-name>order</cmr-field-name></cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> </ejb-jar>

EJB Integration (JCA) EJB Performance Tuning
[thu]

© 2006, Watsh Rajneesh. All Rights Reserved.

86/86

2/9/2008

Clustering Sample Application
[fri]
http://java.sun.com/blueprints/code/projectconventions.html for how to arrange your project build environment. http://java.sun.com/blueprints/code/namingconventions.html for the naming conventions to follow for J2EE applications.

© 2006, Watsh Rajneesh. All Rights Reserved.

Sign up to vote on this title
UsefulNot useful