Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Step 8 - EJB2

Download as pdf or txt
Download as pdf or txt
You are on page 1of 69

Enterprise Java Beans (EJB 2.

0)

About Author

Sumit is a University Gold Medalist, holds master degree in computer application (MCA) &
have been working in IT industry more than eight years (since 2002).
He has extensive experience in ecommerce and EAI domain using J2EE based products like Hybris, ATG,
OFBiz, WCS, WebMethods and Jitterbit.
He is a J2EE architect. He holds PG diploma in operations and also Sun, RUP (Rational Unified Process) and
webMethods certified.

Who should read this?


People who don’t have time to go through thick books but want to know all the aspects of Enterprise Java
Beans.

People who want to be productive in java enterprise application development ASAP.

Above all People who love java.

1|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


1. Introduction
An enterprise means a business organization, and enterprise applications are those software applications that
facilitate various activities in an enterprise.
The term enterprise normally refers to a large organization. The EJB’s are the components suitable for
developing enterprise applications and hence the name Enterprise Java Beans.
1.1 Characteristics of Enterprise Applications
Building applications for enterprise has always been challenging. Some of the factors that contribute to this
challenge and complexity are:
• Diversity of information needs
• Complexity of business processes
• Diversity of applications
These factors are very common and enterprises incur a tremendous cost to build and manage applications that
face these challenges.
1.2 Important Factors in Development of Enterprise Applications
• Programming Productivity (Service Infrastructure)
• Reliability and Availability (Transaction Processing, Clustering, Load Balancing)
• Security
• Scalability (Clustering)
• Integration (JCA)
1.3 Is JAVA (or J2EE) the Answer?
The J2EE (Java 2 Enterprise Edition) is supposed to be highly suitable technology for developing enterprise
applications due to following reasons:
• Platform Independence
• Managed Objects (Container-centric architecture)
• Reusability (EJB-Business Components)
• Modularity (Components + tiers)
Note: J2EE meets almost all of these requirements. The idea behind the J2EE platform is to provide a simple,
unified standard for distributed applications.

2|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


2. The 3-Tier/n-tier Architecture

The three tier architecture evolved to solve the problems faced in 2-tier architecture.

User Interface First Tier


(Presentation Layer)

Second tier
or
Application Logic
Middle tier
(Business Layer)

Third Tier
(Data Layer)

XML
DB Flat Files
Document

Typical Three Tier Architecture

3. J2EE Application Architecture Overview


A J2EE- based application (or any distributed system for that matter) can in general be classified into a set of
layers as shown below:

Layer Name Responsibility Implementation Technologies


1. Presentation User Interface JSP/HTML/JavaScript, AWT
(View)
2. Application Use-case UI workflow, Servlets, JavaBeans and JSP
(Fine-grained syntactic validation,
Controller) interaction with services.
3. Services Controlling Transactions, EJB Session Beans or Simple Java Classes
(Controller) business/workflow logic,
acting as facade.
4. Domain Domain Model, EJB entity beans, POJO (Plain old Java
(Model) domain/business logic. Objects)
5. Persistence Persistence storage of O/R Mappers, OODBMS, XML, Flat Files
domain objects (state)

3|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


4. J2EE Platform
J2EE is one of the best solutions that we have had so far for meeting the demand of today’s enterprise. J2EE
specifies both the infrastructure for managing your applications, and the service API’s for building your
application. It Provides:
• A set of Java extension APIs to build applications. These API’s define a programming model for J2EE
applications.
• A run-time infrastructure for hosting and managing applications. This is the server runtime in which your
applications reside. This is also known as container.
4.1 J2EE APIs
These are some of the APIs supported by the J2EE platform:
• JDBC (Java Data Base Connectivity)
• EJB (Enterprise Java Bean)
• Java Servlet
• JSP (Java Server Pages)
• JMS (Java Messaging Services)
• JTA (Java Transaction API)
• Java Mail
• JAXP (Java API for XML Parsing/Processing)
• JCA (Java Connector Architecture)
• JAAS (Java Authentication and Authorization Service)
• RMI-IIOP (RMI – Internet Inter ORB Protocol)
• JNDI (Java Naming and Directory Interface)
4.2 J2EE Server/Container Architecture (container centric)
A J2EE container is a runtime to manage application components developed according to the API
specifications, and to provide access to the J2EE API’s. It is container centric i.e. components are managed by
the container.
Container Architecture:

Container/Component Contract

Application Application
Other Component Component Declarative
Container Services
Services
Application
Component
Deployment Deployment
Descriptor Descriptor
Deployment
Descriptor

Container Service APIs

4|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


Enterprise Java Beans
1. Overview
An enterprise java bean is a server-side software component that can be deployed in a distributed multitier
environment.

Why we need an application server to deploy Ejbs?


EJB servers give you a bunch of services, so that you don’t have to write them yourself:
• Transaction Management
• Security
• Concurrency
• Networking
• Resource management
• Persistence
• Messaging
• Deploy time customization

Your beans run under the control (and protection) of the EJB server. The server steps into the middle of every
method call from a client to a bean and insert the “services” like security, transactions, and persistence.

5|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


2. Types of Beans

Session beans: Session beans model business processes. They are like verbs because they are actions. The
action could be anything, such as adding numbers, accessing a database, calling a legacy system, or calling
other enterprise beans. Examples include a pricing engine, a workflow engine, a catalog engine, a credit card
authorizer, or a stock-trading engine.

Entity beans: Entity beans model business data. They are like nouns because they are data objects—that is,
Java objects that cache database information. Examples include a product, an order, an employee, a credit card,
or a stock. Session beans typically harness entity beans to achieve business goals, such as a stock-trading engine
(session bean) that deals with stocks (entity beans).
Message-driven beans: Message-driven beans are similar to session beans in that they are actions. The
difference is that you can call message-driven beans only by sending messages to those beans. Examples of
message-driven beans include beans that receive stock trade messages, credit card authorization messages, or
workflow messages. These message driven beans might call other enterprise beans as well. Messaging put
asynchronous behavior in the application.

6|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


3. Clients of EJB Component System
The following diagram shows some of the many possibilities of clients interacting with an EJB component
system.

4. Distributed Objects and Middleware


Distributed objects are great because they allow you to break up an application across a network. However, as a
distributed object application gets larger, you need help from middleware services, such as transactions, security
etc.

Implicit Middleware (or Declarative Middleware or Request Interceptor)


The crucial difference between systems of the past (transaction processing monitors such as TUXEDO or CICS,
or traditional distributed object technologies such as CORBA, DCOM, or RMI) and the newer, component-
based technologies (EJB, CORBA Component Model, and Microsoft.NET) is that in this new world, you
can harness complex middleware in your enterprise applications without writing to middleware APIs. This is
shown in the next figure, and works as follows:
1. Write your distributed object to contain only business logic. Do not write to complex middleware APIs.
For example, this is the code that would run inside the distributed object:
transfer(Account account1, Account account2, long amount) {
// 1: Subtract the balance from one account, add to the other
}

7|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


2. Declare the middleware services that your distributed object needs in a separate descriptor file, such
as a plain text file. For example, you might declare that you need transactions, persistence, and a security
check.
3. Run a command-line tool provided for you by the middleware vendor. This tool takes your descriptor file as
input and generates an object that we’ll call the request interceptor.
4. The request interceptor intercepts requests from the client, performs the middleware that your distributed
object needs (such as transactions, security, and persistence), and then delegates the call to the distributed
object.

The values of implicit middleware are:

Easy to write: You don’t actually write any code to middleware APIs; rather, you declare what you need in a
simple text file. The request interceptor provides the middleware logic for you transparently. You focus away
from the middleware and concentrate on your application’s business code. This is truly divide and conquer!
Easy to maintain: The separation of business logic and middleware logic is clean and maintainable. It is less
code, which makes things simpler. Furthermore, changing middleware does not require changing application
code.
Easy to support: Customers can change the middleware they need by tweaking the descriptor file. For
example, they can change how a security check is done without modifying source code. This avoids upgrade
headaches and intellectual property issues.

8|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


5. What Constitutes an Enterprise Bean?
An enterprise bean component is not a single monolithic file—a number of files work together to make up an
enterprise bean.

For e.g. writing a SessionBean we require


1. A bean class that implements SessionBean interface.
2. Two remote interfaces, one extending EJBObject interface and other extends EJBHome interface.
3. Deployment descriptor, ejb-jar.xml file having declaration of the beans, their remote interfaces and what
they expect from container.

5.1 The EJB Object


Enterprise beans are not full-fledged remote objects. When a client wants to use an instance of an enterprise
bean class, the client never invokes the method directly on an actual bean instance. As a component developer,
this means your life is simplified greatly because you can rapidly develop components without writing,
debugging, or maintaining code that calls middleware APIs.
The EJB object is a surrogate object that knows about networking, transactions, security, and more. It is an
intelligent object that knows how to perform intermediate logic that the EJB container requires before a method
call is serviced by a bean class instance. An EJB object is the request interceptor, or the glue, between the client
and the bean. EJB objects replicate and expose every business method that the bean itself exposes. EJB objects
delegate all client requests to beans.
EJB Object is depicted below:

You should think of EJB objects as physical parts of the container; all EJB objects have container-specific code
inside of them. (Each container handles middleware differently and provides different qualities of service.)
Because each bean’s EJB object is different, your container vendor generates the class file for your EJB objects
automatically.
Each EJB container ships with a suite of glue-code tools. These tools are meant to integrate beans into the EJB
container’s environment. The tools generate helper Java code—stubs, skeletons, data access classes, and other
classes that this specific container requires. Bean providers do not have to think about the specifics of how each
EJB container works because the container’s tools generate its own proprietary Java code automatically.

The container’s glue-code tools are responsible for transforming an enterprise bean into a fully managed,
distributed server-side component. This involves logic to handle resource management, life cycle, state
management, transactions, security, persistence, remote accessibility, and many other services. The generated
code handles these services in the container’s proprietary way.

9|Sumit Agrawal | JAVA Architect | MCC Retail COE| HCLT


5.2 The Home Object
The client cannot instantiate an EJB object directly because the EJB object can exist on a different machine than
the one the client is on. Similarly, EJB promotes location transparency, so clients should never be aware of
exactly where an EJB object resides.
To acquire a reference to an EJB object, your client code asks for an EJB object from an EJB object factory.
This factory is responsible for instantiating (and destroying) EJB objects. The EJB specification calls such a
factory a home object.
The chief responsibilities of home objects are the following:
• Create EJB objects
• Find existing EJB objects (for entity beans)
• Remove EJB objects
Just like EJB objects, home objects are proprietary and specific to each EJB container. They contain interesting
container-specific logic, such as load-balancing logic, logic to track information on a graphical administrative
console, and more. And just like EJB objects, home objects are physically part of the container and are auto-
generated by the container vendor’s tools.

5.3 Deployment Descriptors


To inform the container about your middleware needs, you as a bean provider must declare your components’
middleware service requirements in a deployment descriptor file. For example, you can use a deployment
descriptor to declare how the container should perform lifecycle management, persistence, transaction control,
and security services. The container inspects the deployment descriptor to fulfill the requirements that you lay
out. The deployment descriptor is the key to implicit middleware.
For example, you can use a deployment descriptor to specify the following requirements of your bean.
Bean management and lifecycle requirements
Persistence requirements (entity beans only)
Transaction requirements
Security requirements

10 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Introduction to Session Beans
1. Introduction
A session bean is a relatively short-lived component. It has roughly the lifetime equivalent of a session or
lifetime of the client code that is calling the session bean.
For example, if the client code contacted a session bean to perform order entry logic, the EJB container is
responsible for creating an instance of that session bean component. When the client later disconnects, the
application server may destroy the session bean instance.
The length of the client’s session generally determines how long a session bean is in use—that is where the term
session bean originated.
2. Session Bean Subtypes
The two subtypes of session beans are:
1. stateful session beans and
2. stateless session beans.
2.1 Stateful Session Beans
A stateful session bean is a bean that is designed to service business processes that span multiple method
requests or transactions. To accomplish this, stateful session beans retain state on behalf of an individual client.
If a stateful session bean’s state is changed during a method invocation, that same state will be available to that
same client upon the following invocation.
Example: As a user accesses an online e-commerce web-site, the user can add products to the online shopping
cart. Each time the user adds a product, we perform another request. The consequence of such a business
process is that the components must track the user’s state (such as a shopping cart state) from request to request.
2.2 Stateless Session Beans
A stateless session bean is a bean that holds conversations that span a single method call.
 They are stateless because they do not hold multi-method conversations with their clients.
 After each method call, the container may choose to destroy a stateless session bean, or recreate it, clearing
itself out of all information pertaining to past invocations. It also may choose to keep your instance around,
perhaps reusing it for all clients who want to use the same session bean class. The exact algorithm is
container specific.
 Expect your bean to forget everything after each method call, and thus retain no conversational state from
method to method.
Example: Example of a stateless session bean is a credit card verification component.
The verifier bean takes a credit card number, expiration date, card holder’s name, and amount as input. The
verifier then returns a yes or no answer, depending on whether the card holder’s credit is valid.

11 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Scalability of Session Beans
Because stateless session beans hold no conversational state, all instances of the same stateless session bean
class are equivalent and indistinguishable to a client. Stateless session beans can be pooled, reused, and
swapped from one client to another client on each method call!
So more scalable then stateful session beans.

Stateful session beans are scalable in the term of passivation-activation process. Container can passivate a
stateful session bean on the basis of LRU (Least Recently Used) if it needs space to create new stateful
instances.

Passivation is a serialization process.

12 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
1. Writing HelloWorld
Step 1 – write the first remote interface, having declaration of your business methods

package org.test;

import java.rmi.RemoteException;
import javax.ejb.EJBObject;
public interface HelloRemote extends EJBObject {
public String sayHello() throws RemoteException;
}

Step 2 – write second remote home interface, having a create() method that must return
first Remote interface

package org.test;

import java.rmi.RemoteException;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
public interface HelloHome extends EJBHome {
public HelloRemote create() throws RemoteException, CreateException;
}

Step 3 – write your Queen, I mean Bean class


package org.test;

import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloBean implements SessionBean {
private SessionContext sessionContext;

// 4 callback methods from SessionBean interface


public void setSessionContext(SessionContext sc) {
sessionContext = sc; // single chance to preserve it
System.out.println("In the setSessionContext() method");
}
public void ejbPassivate() {
System.out.println("In the ejbPassivate() method");
}
public void ejbActivate() {
System.out.println("In the ejbActivate() method");
}
public void ejbRemove() {
System.out.println("In the ejbRemove() method");
}

// Bean Rule - matching home's create(). See the return type, here is void
public void ejbCreate() {
System.out.println("In the ejbCreate() method");
}

// your business method


public String sayHello() {
System.out.println("In business method ");
return "Hello World !!!!";
}
}

13 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Step 4 – compile above three files
C:\ejb\src\org\test>javac –classpath c:\jboss\client\jbossall-client.jar –d c:\ejb\ bin
*.java
Step 5 – create a DD META-INF/ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans
2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<enterprise-beans>
<session>
<ejb-name>hello</ejb-name>
<home>org.test.HelloHome</home>
<remote>org.test.HelloRemote</remote>
<ejb-class>org.test.HelloBean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Bean</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>

Step 6 – make a jar file that contains home, remote, bean and DD
First ensure you are having these files
C:\ejb\bin\org\test\HelloRemote.class HelloHome.class HelloBean.class
C:\ejb\bin\META-INF\ejb-jar.xml

C:\ejb\bin>jar –cvf hello.jar org META-INF

Step 7 – copy this jar into jboss\server\default\deploy


C:\ejb\bin>copy hello.har c:\jboss\server\default\deploy

Step 8 – write a client program


public class HelloClient {
public static void main(String[] args) {
try {
Properties p = new Properties();
// The JNDI properties u set depend on which server u r using
p.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
p.put("java.naming.provider.url", "127.0.0.1:1099");
InitialContext ctx = new InitialContext(p);

// Lookup the bean using its's deployment id


Object obj = ctx.lookup("/hello");

// Be good n use RMI remote object narrowing as required by the EJB specification
HelloHome ejbHome = (HelloHome) javax.rmi.PortableRemoteObject.narrow(obj, HelloHome.class);

// use the HelloHome to create a HelloRemote Object.


HelloRemote ejbRemote = ejbHome.create();

// The part we've all been waiting for........


String msg = ejbRemote.sayHello();
System.out.println(msg);
// Important for Stateful session bean
ejbRemote.remove();

}catch (Exception e) {
e.printStackTrace();
}
}
}

14 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Step 9 – compile client program, we used HelloHome and Helloremote refrences in our
client program so these two class files are
required for client compilation

C:\ejb\src>javac –classpath c:\jboss\client\jbossall-client.jar,hello.jar -d c:\ejb\bin


HelloClient.jar

Step 10 – start jboss and wait for server startup message


C:\jboss\bin\run

Step 11 – run the client program


C:\ejb\bin>java –classpath c:\jboss\client\jbossall-client.jar,hello.jar HelloClient

Hello World !!!!


Congratulations!!! If you got this message then you did everything well.

Note
1. when deploying an hello.jar file into a container, the following steps are usually performed:

• The Ejb-jar file is verified. The container checks that the enterprise bean class, the remote interface, and
other items are valid. Any commercial tool should report intelligent errors back to you, such as, “You
need to define an ejbCreate() method in your bean.”

• The container tool generates an EJB object and home object for you.

• The container tool generates any necessary RMI-IIOP stubs and skeletons.

2. We set the Transaction Demarcation in ejb-jar.xml


<transaction-type>Bean</transaction-type>  BMT (Bean Managed Transaction)
Or
<transaction-type>Container</transaction-type>  CMT (Container Managed Transaction)
3. We set the Session Bean type –
<session-type>Stateful</session-type>
Or
<session-type>Stateless</session-type>

15 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
2. Understanding How to Call Beans
There are two different kinds of clients:
Java RMI-IIOP based clients: These clients use the Java Naming and Directory Interface (JNDI) to look up
objects over a network, and they use the Java Transaction API (JTA) to control transactions.
CORBA clients: Clients can also be written to the CORBA standard. This would primarily be useful if you
want to call your EJB components using another language, such as C++. CORBA clients use the CORBA
Naming Service (COS Naming) to look up objects over the network, and they use the CORBA’s Object
Transaction Service (OTS) to control transactions.
Whether you’re using CORBA or RMI-IIOP, your client code typically looks like this:
1. Look up a home object.
2. Use the home object to create an EJB object.
3. Call business methods on the EJB object.
4. Remove the EJB object.
2.1 Looking up a Home Object
One of the goals of EJB is that your application code should be “write once, run anywhere.” If you deploy a
bean onto one machine and then switch it for a different machine, your code should not change because it is
location transparent.
EJB achieves location transparency by leveraging naming and directory services. Naming and directory
services are products that store and look up resources across a network. Some examples of directory service
products are the iPlanet Directory Server, Microsoft’s Active Directory, and IBM’s Lotus Notes Domino
Server.
Corporations traditionally have used naming and directory services to store usernames, passwords, machine
locations, printer locations, and so on. EJB servers exploit naming services to store location information for
resources that your application code uses in an enterprise deployment.
These resources could be:
(i) EJB home objects
(ii) Database Drivers

By using naming services, you can write application code that does not depend on specific machine names or
locations. This is all part of EJB’s location transparency, and it keeps your code portable.
If you decide later that resources should be located elsewhere, your code does not need to be rebuilt because the
naming service can simply be updated to reflect the new resource locations. This greatly enhances maintenance
of a multitier deployment that may evolve over time. This becomes absolutely necessary when purchasing
prewritten software (such as enterprise beans), because your purchased components’ source code will likely not
be made available to you to change.
Note: - While naming and directory servers have typically run standalone, they can also run in the same process
as the application server. Many containers are written in Java, and so their naming and directory services are
just bunch of Java classes that run inside of the container. Unless you’re using CORBA, the de facto API used
to access naming and directory services is the Java Naming and Directory Interface (JNDI). JNDI adds value to
your enterprise deployments by providing a standard interface for locating users, machines, networks, objects,
and services. For example, you can use the JNDI to locate a printer on your corporate intranet. You can also use
it to locate a Java object or to connect with a database. In EJB, JNDI is used to lookup home objects. JNDI is
also useful for locating resources across an enterprise deployment, including database resources, etc.

16 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
2.2 How to Use JNDI to Locate Home Objects?
To achieve location transparency, EJB containers mask the specific locations of home objects from your
enterprise beans’ client code. Clients do not hard-code the machine names that home objects reside on; rather,
they use JNDI to lookup home objects. For clients to locate a home object, you must provide a nickname for
your bean’s home object. Clients will use this nickname to identify the home object it wants. For example, our
Hello World example might have a nickname hello. You specify this nickname using the proprietary vendor-
specific files that are bundled with your bean
When you deploy your bean into the container, the container automatically binds the nickname hello to the
home object. Then any client on any machine across a multitier deployment can use that nickname to find home
objects, without regard to physical machine locations. Clients use the JNDI API to do this. JNDI goes over the
network to some naming service, or JNDI tree, to look for the home object, perhaps contacting one or more
naming services in the process. Eventually the home object is found, and a reference to it is returned to the
client.

This is shown in the following figure:

Properties p = new Properties();

// The JNDI properties u set depends on which server u r using


p.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
p.put("java.naming.provider.url", "127.0.0.1:1099");

InitialContext ctx = new InitialContext(p);

// Lookup the bean using its's deployment nick name


Object obj = ctx.lookup("/hello");

17 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Or
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory")
props.put(Context.PROVIDER_URL , "t3://localhost:7001");
We can also pass the environment information from the command line at the time of running the client:
java –Djava.naming.factory.initial= weblogic.jndi.WLInitialContextFactory -Djava.naming.provider.url=
t3://localhost:7001 HelloClient

Note – keep these 10 points always in your mind


1. Your session or entity bean can have both local and remote interfaces. If remote interfaces are provided it
means you are exposing your bean to outer world (JVM) indirectly.

2. An EJB never communicate with remote/local client directly, all calls comes through either remote or local
Interface objects. EJB class even not implements any remote interface. It makes your bean safe and you do not
worry to implement methods already present in EJBObject interface.
But, what if I want to ensure that all business methods placed in EJBObject are implemented inside the EJB
class.
A Solution: There is an alternative way to preserve compile-time checks of your method signatures. The
approach is to contain your bean’s business method signatures within a common super-interface that your
remote interface extends and your bean implements. You can think of this super-interface as a business
interface that defines your business methods and is independent of EJB.

3. Your container will implement all classes for remote/local interfaces at the time of deployment. It will also
create two stubs for remote components (EJBHome and EJBObject)
4. It will bind home stubs to JNDI tree, when client will lookup your EJB, this stub will be returned to client
JVM.

5. When you will call create method of home, home will return you EJBObject’s class stub.

6. This way client will be having, both stubs, now it is up to you what method of which stub you (client) want to
call.

7. There are lot of activities that we can do inside callback and our business methods. But it differs from bean
type to bean type and also method to method.

8. See in above bean interfaces and home interfaces, there are no create or ejbCreate() method. But when we put
create() in home then we have to put matching ejbCreate() in bean and some time matching ejbPostCtreate()
also. These type of methods and restrictions are called Bean Law, that you have to follow.

9. ejb-jar.xml called Deployment Descriptor(DD), where we will declare our bean and specify it’s behaviors.
DD is divided into two parts enterprise-beans and assembly-descriptor.

10. There are four roles are defined in Enterprise Bean Application
a. Bean provider – code the bean and remote interfaces, also write first part of DD
b. Bean Assembler – assemble different bean component and write second part of DD
c. Bean Deployer - study DD and resolve external dependency.
d. Container or Server Provider

18 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Stateful Session Bean –
1. We can maintain client specific information at application server

2. If your client is servlet then you may have two sessions HttpSession at Web server and specific SessionBean
instance kept for you at Application server. So it is client responsibility to inform Application server when to
invalidate the session bean instance. It can be done by ejbRemote.remove();

3. It’s home can have overloaded create() method. Like


HelloRemote create(String username) throws RemoteException, CreateException;
HelloRemote create(String name, String likes, String dislikes) throws RemoteException, CreateException;

4. Bean Rule – you must be having all matching create in bean class.

5. All methods placed in remote interfaces must throw RemoteException, create must throw CreateException
also.

6. Bean Rule - your bean will not implement remote interfaces but you have to put all business method and
ejbCreate method in the bean.

7. For ensuring that all business methods are implemented gracefully, we can use a trick, create a common
interface that will be extended by the your remote interface HelloRemote and implemented by the HelloBean
class also.

8. Return type of business method must be either primitive or Serializable.

9. Since it maintains client specific information and if a client is not active then application server can passivate
your bean for scalability.

10. Your bean instance will die if client called remove or bean method throws a Unchecked runtime exception.

11. One home for particular bean will serve all its home stub and remote stub

Stateless Session Bean –


1. NO client specific information, so single create() method without any parameter.

2. NO client specific instance so Application server can maintain Bean pool for scalability.

3. No client specific instance so remove called by client will not matter. AS will decide when to create new
instances and when to destroy or send back to pool.

4. No client specific information is preserved inside the bean so no need of passivation and activation cycle.

5. on calling create() method remote EJBObject will be created but when client will invoke a business method
then only bean will come out of pool and will server the method. So a stateless bean instance can serve for
several business methods call in its life, without knowing for which client.

6. Keep in mind a stateless bean instance can not be shared when called remote business method is in execution.
An instance will serve that request.

19 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Now you can understand this sequence diagram –

Life Cycles of Stateless Session Bean

20 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Life Cycles of Stateful Session Bean

21 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Deploying and Running Application on Weblogic
3.1 Weblogic Folder Structure
Some of the important folders are as follows assuming that weblogic is installed in the d:\bea folder i.e. the
home folder is D:\bea.
D:\bea\weblogic81 – folder containing weblogic server 8.1 files.
D:\bea\user-projects – folder containing weblogic domains and applications.
D:\bea\user-projects\domains – folder containing weblogic domains.
D:\bea\user-projects\domains\mydomain – default weblogic domain.
D:\bea\user-projects\domains\mydomain\applications
-Folder in which .jar or .war file can be dropped to deploy the applications.
3.2 Starting Weblogic Server
You need to follow these steps to start the weblogic server:
1. Go to folder D:\bea\user-projects\domains\mydomain
2. Execute startWeblogic.cmd
3.3 Starting Weblogic console Application
The console application is a web application that is installed automatically on installing the weblogic server.
This application is used to administer the weblogic server. You can see the status information and can deploy
applications using console application. The console application can be accessed using the url:
http://localhost:7001/console
3.4 Starting Weblogic Builder
The weblogic buider is a tool that comes with the weblogic server. It helps in generating deployment descriptor
and .jar files. You need to follow these steps to start the weblogic builder:
1. Go to folder D:\bea\weblogic81\server\bin
2. Execute startWLBuilder.cmd
3.5 Compiling the Java Files
For compiling the EJB source files, weblogic.jar or j2ee.jar file should be in the classpath. The EJB
APIs are part of this package. The weblogic.jar path can be included in the classpath by giving the following
command:
set classpath=%classpath%;D:\bea\weblogic81\server\lib\weblogic.jar

After adding the weblogic.jar file to classpath, compile the EJB source files:
Compile the client java file also. HelloClient.java: Only change is
Hashtable props = new Hashtable();
props.put(Context.INITIAL_CONTEXT_FACTORY,
"weblogic.jndi.WLInitialContextFactory");
props.put(Context.PROVIDER_URL , "t3://localhost:7001");
InitialContext ic = new InitialContext(props);

Note: The weblogic.jar, Hello.class (remote interface) and HelloHome.class (home interface) should be in the
classpath while compiling the client.

22 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3.6 Generating XML Files (Deployment Descriptors) and .jar File
The deployment descriptors can be generated automatically with the help of weblogic builder. Follow these
steps for generating XML files:
1. Start WLBuilder by executing startWLBuilder.cmd
2. Select “open” option from file menu.
3. Chose folder D:\hello\ejb (This folder contains the deployment/packaging structure as recommended by
J2EE Specifications).
4. Save XML files (ejb-jar.xml and weblogic-ejb-jar.xml) by clicking on save option under File menu.
5. Save .jar file by clicking on Archive option under File menu).
3.7.1 How to create .jar File Manually?
The .jar file can be created manually as follows:
D:\hello\ejb>jar –cf hello.jar *;
3.8 Deployment
There are two ways of deploying an EJB:
1. By dropping .jar file in folder “D:\bea\user-projects\domains\mydomain\applications”
2. Deploying using console application.
3.8.1 Dropping .jar File
You can deploy an EJB by simply dropping the .jar file (say hello.jar) in the applications folder “D:\bea\user-
projects\domains\mydomain\applications”.
3.8.2 Deploying using console Application
You can also deploy the EJB using console application. You need to follow the following steps:
1. Access console application using the url “http://localhost:7001/console”.
2. Click on Deployment option (left panel).
3. Click on EJB Modules (left panel).
4. Click on “Deploy a new EJB Module” (right panel).
5. Select the .jar file and click on “Target” button.
6. Change the name by which EJB will be deployed if you wish and then click on “Deploy” button.
7. Click on the tab “Testing”.
8. Click on the link “Test This EJB” to check whether bean has been deployed successfully.

23 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Java Messaging Service (JMS) and Message Driven Bean (MDB)
Synchronous Communications
If a client makes a request of a remote server, the thread that made the request will block until the response
comes back from the server.

Asynchronous Communications
A client sends a request to the server and then continues doing other work, while the server possibly invokes
some kind of callback on the client when the request is complete. This is where the Java Message Service
(JMS) comes in.

Like JDBC and JNDI, JMS is a specification and as of J2EE 1.3 compliant servers are required to provide a full
JMS provider.

Asynchronous messaging usually comes in two flavors: Queue and Topic

Queue – A message can be addressed and sent to a single receiver (producer-consumer/point-to-point/one-


to-one),

Topic – A message can be published to a particular channel and any receiver that subscribes to that channel will
receive the message (publish-subscribe/one-to-many).

The Concept –
Client using Messaging API will create a
Message Object that will hold the data to be
communicated and will put this message
into server provided MOM.
Client subscribed for particular message
(configured on server) will receive this
message in some callback method.
Simple Observer Pattern ;-)

24 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Implementation Steps

1. Application Server comes with Topic and Queue connection factories already bind in JNDI, so
lookup them first.
Properties properties = new Properties();
properties.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.provider.url", "127.0.0.1:1099");

Context ctx = new InitialContext(properties);


QueueConnectionFactory connectionFactory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory");

2. Now using this factory we can create a connection with Queue or Topic
QueueConnection connection = connectionFactory.createQueueConnection();

3. We can open one or multiple Queue or Topic session(s) on this connection.


QueueSession session =
connection.createQueueSession(false,QueueSession.AUTO_ACKNOWLEDGE);

The boolean parameter in the method indicates whether the Session object will be transacted. A
transacted Session automatically manages outgoing and incoming messages within a transaction.

4. Now we can create QueueSender/QueueReceiver or TopicPublisher/TopicSubscriber


Queue queue = (Queue) ctx.lookup("queue/Hello");
QueueSender sender = session.createSender(queue);
Here we refer to particular named queue or topic, servers comes with example topic and queues
configuration. We can declare our own named queue or topic in DD or some server conf files.

5. Create and send Message


TextMessage msg = session.createTextMessage("Hello World!!!");
sender.send(msg);
Message Types

TextMessage A standard Java string


ObjectMessage A serializable Java object
MapMessage A set of name/value pairs where values are Java primitives
StreamMessage A stream of Java primitives
BytesMessage A stream of uninterpreted bytes

25 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
HelloWorld – Sender.java
public class Sender {
public static void main(String args[]) throws Exception {

Properties props = new Properties();


props.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
props.put("java.naming.provider.url", "127.0.0.1:1099");

Context context = new InitialContext(props);


TopicConnectionFactory tcf = (TopicConnectionFactory) context
.lookup("TopicConnectionFactory");
TopicConnection conn = tcf.createTopicConnection();
TopicSession session = conn.createTopicSession(false,
TopicSession.AUTO_ACKNOWLEDGE);

Topic topic = (Topic) context.lookup("topic/example");


TopicPublisher sender = session.createPublisher(topic);
TextMessage tm = session.createTextMessage("Hello World");
sender.publish(tm);

sender.close();
session.close();
}
}
HelloWorld – Receiver.java
public class Receiver implements MessageListener {

public void onMessage(Message msg) {


TextMessage tm = (TextMessage) msg;
try {
System.out.println("Incoming message: " + tm.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
public static void main(String args[]) throws Exception {
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
props.put("java.naming.provider.url", "127.0.0.1:1099");
Context context = new InitialContext(props);
TopicConnectionFactory tcf = (TopicConnectionFactory) context
.lookup("TopicConnectionFactory");
TopicConnection conn = tcf.createTopicConnection();
TopicSession session = conn.createTopicSession(false,
TopicSession.AUTO_ACKNOWLEDGE);
Topic topic = (Topic) context.lookup("topic/example");
TopicSubscriber reciever = session.createSubscriber(topic);
reciever.setMessageListener(new Receiver());
conn.start();

// leave it open for 2 minutes:


Thread.sleep(120000);
session.close();
conn.close();
}
}
Just run the jboss server, and then run the Receiver program then the Sender program.

26 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
So two or more client will be communicating to each other asynchronously by using JMS API.

MessageListener - The pub/sub messaging model in JMS includes an in-process Java event
model for handling incoming messages. An object simply implements the listener interface,
in this case the MessageListener, and then is registered with the TopicSubscriber. When
the TopicSubscriber receives a message from its topic, it invokes the onMessage( ) method
of its MessageListener objects.

Message - It has two parts: the message data itself, called the payload or message body, and the message
headers and properties.
Message Headers
Automatically assigned headers

JMSDestination - The JMSDestination header identifies the destination with either a


Topic or Queue object, both of which are Destination types.

JMSDeliveryMode - There are two types of delivery modes in JMS: persistent and
nonpersistent. A persistent message should be delivered once-and-only-once, which
means that if the JMS provider fails, the message is not lost; it will be delivered after
the server recovers. A nonpersistent message is delivered at-most-once, which means
that it can be lost permanently if the JMS provider fails.

JMSMessageID - The JMSMessageID is a String value that uniquely identifies a


message.

JMSTimestamp - The JMSTimestamp is set automatically by the message producer


when the send( ) operation is invoked.
// Set time to live as 1 hour (1000 millis x 60 sec x 60 min)
topicPublisher.setTimeToLive(3600000);
By default the timeToLive is zero (0), which indicates that the message doesn't expire.
JMSExpiration - A Message object's expiration date prevents the message from being delivered to consumers
after it has expired. This is useful for messages whose data is only valid for a period of time:
TopicPublisher topicPublisher = topicSession.createPublisher
JMSRedelivered - The JMSRedelivered header indicates that the message was redelivered to the consumer.
The JMSRedelivered header is true if the message is redelivered, and false if it's not.
JMSPriority - The message producer may assign a priority to a message when it is delivered. There are two
categories of message priorities: levels 0-4 are gradations of normal priority; levels 5-9 are gradations of
expedited priority. The message servers may use a message's priority to prioritize delivery of messages to
consumers - messages with an expedited priority are delivered ahead of normal priority message
topicPublisher.setPriority(9);
Developer-assigned headers
27 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
JMSReplyTo - In some cases, a JMS message producer may want the consumers to reply to a message.
The JMSReplyTo header, which contains a javax.jms.Destination, indicates which address a JMS consumer
should reply to. A JMS consumer is not required to send a reply:
message.setJMSReplyTo(topic);

JMSCorrelationID - The JMSCorrelationID provides a header for associating the current message with some
previous message or application-specific ID. In most cases the JMSCorrelationID will be used to tag a message
as a reply to a previous message identified by a JMSMessageID, but the JMSCorrelationID can be any value,
not just a JMSMessageID :
message.setJMSCorrelationID(identifier);

JMSType - JMSType is an optional header that is set by the JMS client. Its main purpose is to identify the
message structure and type of payload.

Properties
Properties act like additional headers that can be assigned to a message. They provide the developer with more
information about the message.
TextMessage message = pubSession.createTextMessage( );
message.setText(text);
message.setStringProperty("username",username);
publisher.publish(message);

TopicSubscriber.receive( )
The default behavior of the receive( ) method is to block program execution until a message is retrieved from
the message server. The receive( ) method effectively changes the pub/sub model from a "push" to a "pull"
model.

Message receive( );
Message receive(long timeout);
Message receiveNoWait( );

Durable Subscriptions
While a durable subscriber is disconnected from the JMS server, it is the responsibility of the server to store
messages the subscriber misses. When the durable subscriber reconnects, the message server sends it all the
unexpired messages that accumulated. This behavior is commonly referred to as store-and-forward messaging.
Store-and-forward messaging is a key component of the guaranteed messaging solution. Durable subscriptions
make a JMS consumer tolerant of disconnections, whether they are intentional or the result of a partial failure.
TopicSubscriber subscriber = session.createDurableSubscriber(topic,"Mr durable");

Publishing the Message Persistently


publisher.publish(message,javax.jms.DeliveryMode.PERSISTENT,javax.jms.Message.DEFAULT_PRIORIT
Y,1800000);

28 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Message Acknowledgments

AUTO_ACKNOWLEDGE
The producer's perspective
Under the covers, the TopicPublisher.publish( ) or QueueSender.send( ) methods are synchronous. These
methods are responsible for sending the message and blocking until an acknowledgment is received from the
message server. Once an acknowledgment has been received, the thread of execution resumes and the method
returns; processing continues as normal. The underlying acknowledgment is not visible to the client
programming model. If a failure condition occurs during this operation, an exception is thrown and the message
is considered undelivered.

The server's perspective


The acknowledgment sent to the producer (sender) from the server means that the server has received the
message and has accepted responsibility for delivering it. From the JMS server's perspective, the
acknowledgment sent to the producer is not tied directly to the delivery of the message. They are logically two
separate steps. For persistent messages, the server writes the message out to disk (the store part of store-and-
forward), then acknowledges to the producer that the message was received. For nonpersistent messages, this
means the server may acknowledge the sender as soon as it has received the message and has the message in
memory. If there are no subscribers for the message's topic, the message may be discarded depending on the
vendor.

The consumer's perspective


There are also rules governing acknowledgments and failure conditions from the consumer's perspective. If the
session is in AUTO_ACKNOWLEDGE mode, the JMS provider's client runtime must automatically send an
acknowledgment to the server as each consumer gets the message. If the server doesn't receive this
acknowledgment, it considers the message undelivered and may attempt redelivery.

CLIENT_ACKNOWLEDGE

The use of CLIENT_ACKNOWLEDGE allows the application to control when the acknowledgment is sent. For
example, an application can acknowledge a message -thereby relieving the JMS provider of its duty - and
perform further processing of the data represented by the message. The key to this is the acknowledge( )
method on the Message object
public void onMessage(javax.jms.Message message){
int count = 1000;
try {
// Perform some business logic with the message
...
message.acknowledge( );
// Perform more business logic with the message
...
} catch (javax.jms.JMSException jmse){
// Catch the exception thrown and undo the results
// of partial processing
...
}
}
DUPS_OK_ACKNOWLEDGE
Specifying the DUPS_OK_ACKNOWLEDGE mode on a session instructs the JMS provider that it is OK to send a
message more than once to the same destination. An application that is tolerant of receiving duplicate messages
can use the DUPS_OK_ACKNOWLEDGE mode.

29 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Message Driven Bean – MDB
The MessageDrivenBean type is a enterprise bean component that is designed to consume asynchronous JMS
messages. It can consume JMS messages, and process them in the same robust component-based infrastructure
that session and entity beans enjoy.

Big Benefit - Concurrent processing


The EJB container actually instantiates many instances of the same message-driven bean and keeps those
instances in pool.

A message-driven bean can consume messages concurrently in a robust server environment; it is capable of
much higher throughput and better scalability than most traditional JMS clients.
1. public class HelloBean implements MessageDrivenBean, MessageListener {
MessageDrivenContext msgContext;

public void setMessageDrivenContext(MessageDrivenContext context) {


msgContext = context;
}
public void ejbCreate() {
}
public void ejbRemove() {
}

public void onMessage(Message message) {


if (message instanceof TextMessage) {
TextMessage txtMsg = (TextMessage) message;
try {
System.out.println("Message Received...." + txtMsg.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

2. public class JMSClient {


public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.put("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
properties.put("java.naming.provider.url", "127.0.0.1:1099");

Context ctx = new InitialContext(properties);


QueueConnectionFactory connectionFactory = (QueueConnectionFactory) ctx
.lookup("ConnectionFactory");
QueueConnection connection = connectionFactory.createQueueConnection();
QueueSession session = connection.createQueueSession(false, 1);
Queue queue = (Queue) ctx.lookup("queue/Hello");
QueueSender sender = session.createSender(queue);
sender.setDeliveryMode(1);
sender.setPriority(9);

TextMessage msg = session.createTextMessage("Hello World!!!");

}
}

30 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. META-INF/ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
<enterprise-beans>
<message-driven>
<ejb-name>Hello</ejb-name>
<ejb-class>org.test.HelloBean</ejb-class>
<transaction-type>Container</transaction-type>
<acknowledge-mode>Auto-acknowledge</acknowledge-mode>
<message-driven-destination>
<destination-type>javax.jms.Queue</destination-type>
</message-driven-destination>
</message-driven>
</enterprise-beans>
</ejb-jar>

4. create a jar and put it in deploy then run the client we wrote in first step.
If you got this message Hello World!!! Then you did everything well.

MDB Lifecycle

31 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Entity Beans
1. Introduction
Entity beans are persistent objects that can be stored in permanent storage. These are objects that know how to
render themselves into persistent storage. They use some persistence mechanism, such as serialization, O/R
mapping to a relational database, or an object database. These kinds of objects represent data—simple or
complex information that you’d like saved.

32 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Examples:
• Bank account information, such as account number and balance.
• Human resources data, such as names, departments, and salaries of employees.
• Lead tracking information, such as names, addresses, and phone numbers of prospective customers that
you want to keep track of over time
Entity beans are these persistent data components. Entity beans are enterprise beans that know how to persist
themselves permanently to a durable storage like a database or legacy system.
Entity beans are very different from session beans. Session beans model a process or workflow. Entity beans, on
the other hand, contain core business data—product information, bank accounts, orders, lead tracking
information, customer information, and more.
An entity bean does not perform complex tasks or workflow logic, such as billing a customer. Rather, an entity
bean is the customer itself. Entity beans represent persistent state objects
The term entity bean is grossly overused. Sometimes it refers to an in-memory Java object instance of an entity
bean class, and sometimes it refers to database data that an in-memory Java object instance represents.
The entity bean instance is the in-memory view into the database. It is an instance of your entity bean class.
The entity bean data (or data instance) is the physical set of data, such as a bank account record, stored in the
database.
You should think of an entity bean instance as the following:
• An in-memory Java representation of persistent data.
• Smart enough to know how to read itself from a storage and populate its fields with the stored data.
• An object that can then be modified in-memory to change the values of data.
• Persistable, so that it can be saved back into storage again, thus updating the database data.

2. The Files that make up an Entity Bean


The entity bean is made up of following:
1. The Remote Interface Class
2. The Home Interface Class
3. The Entity Bean Class: It maps to an entity definition in a database schema. For example, an entity
bean class could map to a relational table definition. In this case, an entity bean instance of that class
would map to a row in that table. Your entity bean class can expose simple methods to manipulate or
access that data, such as a method to decrease a bank account balance.
4. The Primary Key Class: It makes every entity bean different. For example, if you have 1 million
different bank account entity beans, each bank account needs to have a unique ID (such as a bank
account ID string) that can never be repeated in any other bank account. A primary key is an object that
may contain any number of attributes. This could be whatever data is necessary to uniquely identify an
entity bean data instance. In some advanced cases, when the entity bean represents a complex
relationship, the primary key might be an entire object. EJB gives you the flexibility to define what your
unique identifier is by including a primary key class with your entity bean. The one rule is that your
primary key class must be serializable and follow the rules for Java object serialization.

33 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Features of Entity Beans
The following sections describe the features of entity beans.
3.1 Entity Beans Survive Failures
Entity beans are long lasting. They survive critical failures, such as application servers crashing, or even
databases crashing. This is because entity beans are just representations of data in a permanent, fault-tolerant
underlying storage. If a machine crashes, the entity bean can be reconstructed in memory. All we need to do is
read the data back in from the permanent database and instantiate an entity bean Java object instance whose
fields contain the data read in from the database.
There is a huge difference between session and entity beans. Entity beans have a life cycle much longer than a
client’s session, perhaps years long, depending on how long the data sits in the database. In fact, the database
records representing an object could have existed before the company even decided to go with a Java-based
solution, because a database structure can be language-independent. This makes sense—you definitely would
want your bank account to last for a few years, regardless of technology changes in your bank.
3.2 Entity Bean Instances Are a View into a Database
When you load entity bean data into an in-memory entity bean instance, you read in the data stored in a
database so that you can manipulate the data within a Java Virtual Machine. However, you should think of the
in-memory object and the database itself as one and the same. This means if you update the in-memory entity
bean instance, the database should automatically be updated as well. You should not think of the in-memory
entity bean as a separate version of the data in the database. The in-memory entity bean is simply a view or lens
into the database.
Of course, in reality there are multiple physical copies of the same data: the in-memory entity bean instance and
the entity bean data itself stored in the database. Therefore, there must be a mechanism to transfer information
back and forth between the Java object and the database. This data transfer is accomplished with two special
methods that your entity bean class must implement, called ejbLoad() and ejbStore().
The ejbLoad() reads the data in from the persistent storage into the entity bean’s in-memory fields. The
ejbStore() saves your bean instance’s current fields to the underlying data storage. It is the complement of
ejbLoad().
The container decides when to calls ejbLoad( ) & ejbStore( ). Your beans should be prepared to accept an
ejbLoad() or ejbStore() call at almost any time (but not during a business method). The container automatically
figures out when each of your instances needs to be refreshed depending on the current transactional state.
You never explicitly call your own ejbLoad() or ejbStore() methods. This is one of the advantages of EJB: You
don’t have to worry about synchronizing your objects with the underlying database. The EJB black box handles
it for you. That is why you can think of the entity bean and the database as the same; there should never be a
time when the two are transitionally out of sync.
The following figure demonstrates when container calls these methods:

34 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3.3 Several Entity Bean Instances may Represent the same Underlying Data
To achieve entity bean instance cache consistency, each entity bean instance needs to be routinely synchronized
with the underlying storage. The container synchronizes the bean with the underlying storage by calling the
bean’s ejbLoad() and ejbStore().
Transactions allow each client request to be isolated from every other request. They enable clients to believe
they are dealing with a single in-memory bean instance, when in fact many instances are behind the scenes.
Transactions give clients the illusion that they have exclusive access to data when in fact many clients are
touching the same data.
3.4 Entity Bean Instances can be Pooled
To save precious time instantiating objects, entity bean instances are recyclable objects and may be pooled
depending on your container’s policy. The container may pool and reuse entity bean instances to represent
different bank account records.
To allow the bean to release and acquire resources, your entity bean class must implement two callback
methods.
The ejbActivate( ) is the callback that your container will invoke on your bean instance when transitioning your
bean out of a generic instance pool.
The ejbPassivate() is the callback that your container will invoke when transitioning your bean into a generic
instance pool.
The container invokes the entity bean’s ejbStore() method prior to passivation. Similarly, just after activation it
calls ejbLoad( ) method.

35 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3.5 There are two ways to Persist Entity Beans
A bean-managed persistent entity bean is an entity bean that must be persisted by hand. In other words, you as
the component developer must write code to translate your in-memory fields into an underlying data store, such
as a relational database or an object database. You handle the persistent operations yourself—including saving,
loading, and finding data—within the entity bean.
You can have your EJB container perform your persistence for you. This is called container-managed
persistence.
The container-managed persistence reduces the size of your beans tremendously because you don’t need to
write JDBC code—the container handles all the persistence for you.
3.6 Creation and Removal of Entity Beans
When an entity bean is initialized in memory during ejbCreate(), it makes sense to create some data in an
underlying database that correlates with the in-memory instance. That is exactly what happens with entity
beans. When a bean-managed persistent entity bean’s ejbCreate() method is called, the ejbCreate() method is
responsible for creating database data.
Similarly, when a bean-managed persistent entity bean’s ejbRemove() method is called, the ejbRemove()
method is responsible for removing database data. If container-managed persistence is used, the container will
modify the database for you, and you can leave these methods empty of data access logic.
Understanding how Entity Beans are Created
In EJB, remember that clients do not directly invoke on beans—they invoke an EJB object proxy. The EJB
object is generated through the home object. Therefore, for each ejbCreate() method signature you define in
your bean, you must define a corresponding create() in the home interface. The client calls the home object’s
create(), which delegates to your bean’s ejbCreate().

36 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
For example, let’s say you have a bank account entity bean class called AccountBean, with a remote interface
Account, home interface AccountHome, and primary key class AccountPK. Given the following ejbCreate()
method in AccountBean:
public AccountPK ejbCreate(String accountID, String owner) throws . . .

you must have this create() in your home interface (notice there is no “ejb” prefix):
public Account create(String accountID, String owner) throws . .

Notice that there are two different return values here. The bean instance returns a primary key (AccountPK),
while the home object returns an EJB object (Account). This makes sense—the bean returns a primary key to
the container (that is, to the home object) so that the container can identify the bean. Once the home object has
this primary key, it can generate an EJB object and return that to the client. We show this process more
rigorously with the sequence diagram in the following figure:

Understanding how Entity Beans are Removed


To destroy an entity bean’s data in a database, the client must call remove() on the EJB object or home object.
This method causes the container to issue an ejbRemove() call on the bean. The following figure shows the
relationship between remove() and ejbRemove(). Note that remove() can be called on either the home object or
the EJB object. The figure happens to assume bean-managed persistence.
Note that ejbRemove() does not mean the in-memory entity bean instance is going to be destroyed; ejbRemove()
destroys only database data. The bean instance can be recycled to handle a different database data instance, such
as a bank account bean representing different bank account.

37 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
The ejbRemove() is a required method of all entity beans, and it takes no parameters. There is only one form of
ejbRemove(). With entity beans, ejbRemove() is not called if the client times out because the lifetime of an
entity bean is longer than the client’s session.

3.7 Entity Beans can be Found


Because entity bean data is uniquely identified in an underlying storage, entity beans can also be found rather
than created. Finding an entity bean is analogous to performing a SELECT statement in SQL. With a SELECT
statement, you’re searching for data from a relational database store.

3.8 You can modify Entity Bean Data without Using EJB
Usually you will create, destroy, and find entity bean data by using the entity bean’s home object. But you can
interact with entity beans in another way, too: by directly modifying the underlying database where the bean
data is stored.

Note: These external database updates could raise cache consistency issues if you’re choosing to cache your
entity beans.

38 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
39 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Bean-Managed Persistent Entity Beans (BMP)
1. Introduction
To write an entity bean class, you write a Java class that implements the javax.ejb.EntityBean interface. This
interface defines a number of required methods that your entity bean class must implement. Most of these
methods are management methods called by your EJB container.
The javax.ejb.EntityBean interface defines callback methods that your bean must implement. The container will
call these methods whenever it wishes.
The javax.ejb.EnterpriseBean Interface
public interface javax.ejb.EnterpriseBean implements java.io.Serializable {}

The javax.ejb.EntityBean interface.


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();
}

2. Finding Existing Entity Beans


The existing entity beans can be found using finder methods whose names start with ejbFind(). Finder methods
do not create new database data—they simply load old entity bean data from storage. You can have many
different finder methods, all of which perform different operations.
Here are some examples:
/**
* Finds the unique bank account indexed by primary key
*/
public AccountPK ejbFindByPrimaryKey(AccountPK key)
throws FinderException { . . . }
/**
* Finds all the product entity beans. Returns a Collection
* of primary keys.
*/
public Collection ejbFindAllProducts()
throws FinderException { . . . }
/**
* Finds all Bank Accounts that have at least a minimum balance.
* Returns a Collection of primary keys.
*/
public Collection ejbFindBigAccounts(int minimum)
throws FinderException { . . . }
/**
* Finds the most recently placed order
*/
public OrderPK ejbFindMostRecentOrder()
throws FinderException { . . . }

40 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
2.1 Rules about Finder Methods
1. All finder methods must begin with ejbFind. This is simply a syntactic rule.
2. You must have at least one finder method, called ejbFindByPrimaryKey. This method finds one unique
entity bean instance in the database based on its unique primary key. Because every entity bean has an
associated primary key, it makes sense that every entity bean class supports this method.
3. You can have many different finder methods, each with different names and different parameters. This
allows you to find using different semantics, as illustrated by the examples above.
4. A finder method must return either the primary key for the entity bean it finds or a collection of primary
keys if it finds more than one. Because you could find more than one data instance in the database, finder
methods can return collection of primary keys.
5. As with ejbCreate(), clients do not invoke your finder methods on the bean instance itself. A finder method
is just like any other method on your entity bean class—clients never directly call any of your bean’s
methods. Rather, clients invoke finder methods on home objects, implemented by the EJB container, that
delegate to your bean. Therefore, for each finder method you define in your bean class, you should define a
corresponding finder in the home interface. Clients call your home object’s finder methods, which delegate
to your bean’s finders.
As with ejbCreate(), the home signature and the bean class signature have a couple of dfferences:
 The entity bean instance returns a primary key to the container, whereas the home object returns an EJB
object to the client.
 The bean class signature is the same as the home signature, except for an extra, mandatory ejb prefix
and that the first letter in the word Find is capitalized.
These signature differences between the home and bean are valid because the bean does not implement the
home interface. Rather, the home object delegates to the bean, so strict signature matching is not needed.
Another interesting aspect of finders is that they can return collections. Your database search may turn up
more than one result and therefore more than one entity bean. Here is the home interface signature:
public Collection findAllProducts() throws FinderException;
and here is the bean implementation signature:
public Collection ejbFindAllProducts() throws FinderException
{ . . . }
The finder process works as follows:
 When the client invokes the home object’s finder, the home object asks a bean to find all primary keys
matching the client’s criteria. The bean then returns a collection of those primary keys to the container.
 When the container receives the collection of keys from the entity bean instance, it creates a collection
of EJB objects, one for each primary key, and returns those EJB objects in its own collection to the
client. The client can then invoke methods on the EJB objects: Each EJB object represents its own
instance of data within the entity bean’s database storage.

41 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Bean-Managed Persistence Example: A Bank Account

Our first example is a simple bank account entity bean. This bank account bean can be used to represent and
manipulate real bank account data in an underlying relational database. The object model for our bank account
is detailed in the above figure. When this bean is used in production, the local interfaces will be used, because
this entity bean will be accessed by other beans that run in-process. However, for testing purposes, and to help
you understand entity beans easily, we don’t want to introduce other beans. Rather, we will connect to this bean
from a standalone application. Since a standalone application is remote, we thus need to use its remote interface.
This is a common issue with EJB programming—to test beans on an individual basis in this manner, you need
to code its remote interface even though you only plan to use the local interface in production. The good news is
that the code is almost identical for the local interface.

Account.java : Remote Interface


1 package examples;
2 import javax.ejb.*;
3 import java.rmi.RemoteException;
4 public interface Account extends EJBObject
5 {
6 public void deposit(double amt)throws AccountException,RemoteException;
7 public void withdraw(double amt)throws AccountException,RemoteException;
8 public double getBalance() throws RemoteException;
9 public String getOwnerName() throws RemoteException;
10 public void setOwnerName(String name) throws RemoteException;
11 public String getAccountID() throws RemoteException;
12 public void setAccountID(String id) throws RemoteException;
13 }

42 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
AccountHome.java: Home Interface
1 package examples;
2 import javax.ejb.*;
3 import java.rmi.RemoteException;
4 import java.util.*;
5 public interface AccountHome extends EJBHome
6 { Account create(String accountID, String ownerName)
7 throws CreateException, RemoteException;
8 public Account findByPrimaryKey(AccountPK key)
9 throws FinderException, RemoteException;
10 public Collection findByOwnerName(String name)
11 throws FinderException, RemoteException;
12 public double getTotalBankValue()
13 throws AccountException, RemoteException;
14 }

AccountException.java: Application Level Exception


1 package examples;
2 public class AccountException extends Exception
3 { public AccountException()
4 {
5 super();
6 }
7 public AccountException(Exception e)
8 {
9 super(e.toString());
10 }
11 public AccountException(String s)
12 {
13 super(s);
14 }
15 }

AccountPK.java: Primary Key


1 package examples;
2 import java.io.Serializable;
3 public class AccountPK implements Serializable
4 { public String accountID;
5 public AccountPK(String id)
6 { this.accountID = id;
7 }
8 public AccountPK()
9 {}
10 public String toString()
11 { return accountID;
12 }
13 public int hashCode()
14 { return accountID.hashCode();
15 }
16 public boolean equals(Object account)
17 { return ((AccountPK)account).accountID.equals(accountID);
18 }
19 }

43 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
AccountBean.java
1 package examples;
2 import java.sql.*;
3 import javax.naming.*;
4 import javax.ejb.*;
5 import java.util.*;
6 public class AccountBean implements EntityBean
7 { protected EntityContext ctx;
8 private String accountID;
9 private String ownerName;
10 private double balance;
11 public AccountBean()
12 {
13 System.out.println("New Bank Account Entity Bean Creation");
14 }
15 //business logic methods
16 public void deposit(double amt) throws AccountException
17 {
18 System.out.println("deposit(" + amt + ") called.");
19 balance += amt;
20 }
21 public void withdraw(double amt) throws AccountException
22 {
23 System.out.println("withdraw(" + amt + ") called.");
24 if(amt > balance)
25 { System.out.println("error in withdraw");
26 throw new AccountException("Your balance is " + balance
27 + "! You cannot withdraw " + amt + "!");
28 }
29 balance -= amt;
30 }
31 public double getBalance()
32 {
33 System.out.println("getBalance() called.");
34 return balance;
35 }
36 public void setOwnerName(String name)
37 {
38 System.out.println("setOwnerName() called.");
39 ownerName = name;
40 }
41 public String getOwnerName()
42 {
43 System.out.println("getOwnerName() called.");
44 return ownerName;
45 }
46 public String getAccountID()
47 {
48 System.out.println("getAccountID() called.");
49 return accountID;
50 }
51 public void setAccountID(String id)
52 {
53 System.out.println("setAccountID() called.");
54 this.accountID = id;
55 }

56 public double ejbHomeGetTotalBankValue() throws AccountException

44 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
57 {
58 PreparedStatement pstmt = null;
59 Connection conn = null;
60 try {
61 System.out.println("ejbHomeGetTotalBankValue()");
62 conn = getConnection();
63 pstmt = conn.prepareStatement(
64 "select sum(balance) as total from accounts");
65 ResultSet rs = pstmt.executeQuery();
66 if ( rs.next() )
67 {
68 return rs.getDouble("total");
69 }
70 }
71 catch(Exception e)
72 {
73 e.printStackTrace();
74 throw new AccountException(e);
75 }
76 finally
77 {
78 try
79 {
80 if(pstmt != null) pstmt.close();
81 }
82 catch (Exception e)
83 {
84 }
85 try
86 {
87 if(conn != null) conn.close();
88 }
89 catch (Exception e)
90 {
91 }
92 }
93 throw new AccountException("Error!");
94 }
95 public Connection getConnection() throws Exception
96 {
97 try
98 {
99 Context ctx = new InitialContext();
100 javax.sql.DataSource ds = (javax.sql.DataSource)
101 ctx.lookup("java:comp/env/jdbc/JDBCPool");
102 return ds.getConnection();
103 }
104 catch(Exception e)
105 {
106 System.err.println("Could not got datasource!");
107 e.printStackTrace();
108 throw e;
109 }
110 }

111 // ejb required methods


112 public void ejbActivate()
113 {
114 System.out.println("ejbActivate() called.");

45 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
115 }
116 public void ejbRemove() throws RemoveException
117 {
118 System.out.println("ejbRemove() called.");
119 AccountPK pk = (AccountPK) ctx.getPrimaryKey();
120 String id = pk.accountID;
121 PreparedStatement pstmt = null;
122 Connection conn = null;
123 try
124 {
125 conn = getConnection();
126 pstmt = conn.prepareStatement
127 ("delete from accounts where id = ?");
128 pstmt.setString(1,id);
129 if(pstmt.executeUpdate() == 0)
130 {
131 throw new RemoveException("Account " + pk +
132 " failed to be removed from the database");
133 }
134 }
135 catch(Exception e)
136 {
137 throw new EJBException(e.toString());
138 }
139 finally
140 {
141 try
142 {
143 if(pstmt != null) pstmt.close();
144 }
145 catch (Exception e)
146 {
147 }
148 try
149 {
150 if(conn != null) conn.close();
151 }
152 catch (Exception e)
153 {
154 }
155 }
156 }
157 public void ejbPassivate()
158 {
159 System.out.println("ejbPassivate () called.");
160 }
161 public void ejbLoad()
162 { System.out.println("ejbLoad() called.");
163 AccountPK pk = (AccountPK) ctx.getPrimaryKey();
164 String id = pk.accountID;
165 PreparedStatement pstmt = null;
166 Connection conn = null;

167 try
168 {
169 conn = getConnection();
170 pstmt = conn.prepareStatement(
171 "select ownername,balance from accounts "+"where id=?");
172 pstmt.setString(1,id);

46 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
173 ResultSet rs = pstmt.executeQuery();
174 rs.next();
175 ownerName = rs.getString("ownername");
176 balance = rs.getDouble("balance");
177 accountID = id;
178 }
179 catch(Exception e)
180 { System.out.println("error on load");
181 throw new EJBException("Account " + pk +
182 " failed to load from database",e);
183 }
184 finally
185 {
186 try
187 {
188 if(pstmt != null) pstmt.close();
189 }
190 catch (Exception e)
191 {
192 }
193 try
194 {
195 if(conn != null) conn.close();
196 }
197 catch (Exception e)
198 {
199 }
200 }
201 }
202 public void ejbStore()
203 {
204 System.out.println("ejbStore() called.");
205 PreparedStatement pstmt = null;
206 Connection conn = null;
207 try
208 {
209 conn = getConnection();
210 pstmt = conn.prepareStatement(
211 "update accounts set ownerName=?,balance=?"+" where id=?");
212 pstmt.setString(1,ownerName);
213 pstmt.setDouble(2,balance);
214 pstmt.setString(3,accountID);
215 pstmt.executeUpdate();
216 System.out.println("updated");
217 }
218 catch(Exception e)
219 {
220 throw new EJBException("Account " + accountID +
221 " failed to save to database",e);
222 }

223 finally
224 {
225 try
226 {
227 if(pstmt != null) pstmt.close();
228 }
229 catch (Exception e)
230 {

47 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
231 }
232 try
233 {
234 if(conn != null) conn.close();
235 }
236 catch (Exception e)
237 {
238 }
239 }
240 }
241 public void setEntityContext(EntityContext ctx)
242 {
243 System.out.println("setEntityContext called");
244 this.ctx = ctx;
245 }
246 public void unsetEntityContext()
247 {
248 System.out.println("unsetEntityContext called");
249 this.ctx = null;
250 }
251 public void ejbPostCreate(String accountID, String ownerName)
252 {
253 }
254 public AccountPK ejbCreate(String accountID, String ownerName)
255 throws CreateException
256 {
257 PreparedStatement pstmt = null;
258 Connection conn = null;
259 try
260 {
261 System.out.println("ejbCreate() called.");
262 this.accountID = accountID;
263 this.ownerName = ownerName;
264 this.balance = 0;
265 conn = getConnection();
266 pstmt = conn.prepareStatement(
267 "insert into accounts(id, ownerName, balance) " + "
268 values(?, ?, ?)");
269 pstmt.setString(1,accountID);
270 pstmt.setString(2,ownerName);
271 pstmt.setDouble(3,balance);
272 pstmt.executeUpdate();
273 return new AccountPK(accountID);
274 }
275 catch(Exception e)
276 {
277 throw new CreateException(e.toString());
278 }

279 finally
280 {
281 try
282 {
283 if(pstmt != null) pstmt.close();
284 }
285 catch (Exception e)
286 {
287 }
288 try

48 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
289 {
290 if(conn != null) conn.close();
291 }
292 catch (Exception e)
293 {
294 }
295 }
296 }
297 public AccountPK ejbFindByPrimaryKey(AccountPK key)
298 throws FinderException
299 {
300 PreparedStatement pstmt = null;
301 Connection conn = null;
302 try
303 {
304 System.out.println("ejbFindByPrimaryKey("+key+")called");
305 conn = getConnection();
306 pstmt = conn.prepareStatement(
307 "select id from accounts where id = ?");
308 pstmt.setString(1,key.toString());
309 ResultSet rs = pstmt.executeQuery();
310 if(rs.next())
311 return key;
312 else
313 throw new FinderException(“Non-existing key”);
314 catch(Exception e)
315 {
316 throw new FinderException(e.toString());
317 }
318 finally
319 {
320 try
321 {
322 if(pstmt != null) pstmt.close();
323 }
324 catch (Exception e)
325 {
326 }
327 try
328 {
329 if(conn != null) conn.close();
330 }
331 catch (Exception e)
332 {
333 }
334 }
335 }

336 public Collection ejbFindByOwnerName(String name)


337 throws FinderException
338 {
339 PreparedStatement pstmt = null;
340 Connection conn = null;
341 Vector v = new Vector();
342 try
343 {
344 System.out.println("ejbFindByOwnerName("+name+") called");
345 conn = getConnection();
346 pstmt = conn.prepareStatement
347 ("select id from accounts where ownerName = ?");

49 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
348 pstmt.setString(1, name);
349 ResultSet rs = pstmt.executeQuery();
350 while(rs.next())
351 {
352 String id = rs.getString("id");
353 v.addElement(new AccountPK(id));
354 }
355 System.out.println("after retrieving");
356 return v;
357 }
358 catch(Exception e)
359 { System.out.println("Finder Exception");
360 throw new FinderException(e.toString());
361 }
362 finally
363 {
364 try
365 {
366 if(pstmt != null) pstmt.close();
367 }
368 catch (Exception e)
369 {
370 }
371 try
372 {
373 if(conn != null) conn.close();
374 }
375 catch (Exception e)
376 {
377 }
378 }
379 }
380 }
AccountClient.java: Client Class
1 import javax.ejb.*;
2 import javax.naming.*;
3 import java.rmi.*;
4 import javax.rmi.*;
5 import java.util.*;
6 import examples.*;
7 public class AccountClient
8 {
9 public static void main(String[] args) throws Exception
10 {
11 Account account = null;
12 try
13 { Hashtable props = new Hashtable();
14 props.put(Context.INITIAL_CONTEXT_FACTORY,
15 "weblogic.jndi.WLInitialContextFactory");
16 props.put(Context.PROVIDER_URL, "t3://everest:7001");
17 InitialContext ic = new InitialContext(props);
18 System.out.println("Before lookup");
19 Object o = ic.lookup("AccountBean");
20 System.out.println("After lookup");
21 AccountHome accountHome = (AccountHome)
22 javax.rmi.PortableRemoteObject.narrow(o, AccountHome.class);
23 System.out.println("Total of all accounts in bank initially= "
24 + accountHome.getTotalBankValue());
25 accountHome.create("123-456-7890", "John Smith1");

50 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
26 System.out.println("after creation");
27 Iterator i =
28 accountHome.findByOwnerName("John Smith1").iterator();
29 if(i.hasNext())
30 {
31 account = (Account) i.next();
32 }
33 else
34 throw new Exception("Could not find account");
35 System.out.println("xxx");
36 System.out.println("Initial Balance = " +
37 account.getBalance());
38 System.out.println("yyy");
39 account.deposit(100);
40 System.out.println("www");
41 System.out.println("After depositing 100, account balance = "
42 + account.getBalance());
43 System.out.println("Total of all accounts in bank now = " +
44 accountHome.getTotalBankValue());
45 AccountPK pk = (AccountPK) account.getPrimaryKey();
46 account = null;
47 account = accountHome.findByPrimaryKey(pk);
48 System.out.println("Found account with ID " + pk +
49 ". Balance = " + account.getBalance());
50 System.out.println(“Now trying to withdraw $150.” +
51 “This should generate an exception..”);
52 account.withdraw(150);
53 System.out.println("zzz");
54 }

55 catch(AccountException e)
56 { System.out.println(e);
57 }
58 catch(Exception e)
59 { System.out.println("Caught Exception......");
60 e.printStackTrace();
61 }
62 catch(Throwable t)
63 { System.out.println("error in withdrawal: ");
64 }
65 finally
66 { try
67 { System.out.println("Destroying account.............");
68 if(account != null)
69 account.remove();
70 }
71 catch(Exception e)
72 { System.out.println("error in deleting the account : ");
73 }
74 }
75 }
76 }
ejb-jar.xml: J2EE specific deployment descriptor

51 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
1 <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans
2 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
3 <!-- Generated XML! -->
4 <ejb-jar>
5 <enterprise-beans>
6 <entity>
7 <ejb-name>AccountBean</ejb-name>
8 <home>examples.AccountHome</home>
9 <remote>examples.Account</remote>
10 <ejb-class>examples.AccountBean</ejb-class>
11 <persistence-type>Bean</persistence-type>
12 <prim-key-class>examples.AccountPK</prim-key-class>
13 <reentrant>False</reentrant>
14 <resource-ref>
15 <res-ref-name>jdbc/JDBCPool</res-ref-name>
16 <res-type>javax.sql.DataSource</res-type>
17 <res-auth>Container</res-auth>
18 </resource-ref>
19 </entity>
20 </enterprise-beans>
21 <assembly-descriptor>
22 <container-transaction>
23 <method>
24 <ejb-name>AccountBean</ejb-name>
25 <method-name>*</method-name>
26 </method>
27 <trans-attribute>Required</trans-attribute>
28 </container-transaction>
29 </assembly-descriptor>
30 </ejb-jar>
weblogic-ejb-jar.xml: Container specific deployment descriptor
1 <!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0
2 EJB//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>
3 <!-- Generated XML! -->
4 <weblogic-ejb-jar>
5 <weblogic-enterprise-bean>
6 <ejb-name>AccountBean</ejb-name>
7 <entity-descriptor>
8 <pool>
9 </pool>
10 <entity-cache>
11 </entity-cache>
12 <entity-clustering>
13 </entity-clustering>
14 </entity-descriptor>
15 <transaction-descriptor>
16 </transaction-descriptor>
17 <reference-descriptor>
18 <resource-description>
19 <res-ref-name>jdbc/JDBCPool</res-ref-name>
20 <jndi-name>JDBCDS</jndi-name>
21 </resource-description>
22 </reference-descriptor>
23 <jndi-name>AccountBean</jndi-name>
24 </weblogic-enterprise-bean>
25 </weblogic-ejb-jar>
3.1 Setting up the Database
52 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Lastly, you need to create the appropriate database table and columns for our bank accounts. You can do this
through your database’s GUI or command-line interface. You should enter the following SQL Data Definition
Language (DDL) statements in your database’s SQL interface:
drop table accounts;
create table accounts (id varchar(64), ownername varchar(64), balance
numeric(18));
This creates an empty table of bank accounts. The first column is the bank account ID (the primary key), the
second column is the bank account owner’s name, and the third column is the bank account balance.
BMP Lifecycle

53 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Container-Managed Persistent Entity Beans (CMP)
1. Introduction
With container-managed persistence (CMP), you don’t implement any persistence logic (such as JDBC) in the
entity bean itself; rather, the EJB container performs storage operations for you.
2. Features of CMP Entity Beans
2.1 CMP Entity Beans are Sub-Classed

CMP have a clean separation between an entity bean and its persistent representation that is, a separation
between the data logic methods (such as logic in your entity bean to add two fields together) and the JDBC.
This separation is valuable because you can modify the persistent representation of an entity bean (such as
changing from a relational to an object database) without affecting the entity bean logic.
To achieve this clean separation, you write your CMP entity bean class to be devoid of any JDBC or other
persistence logic. The container then generates the JDBC by subclassing your entity bean class.
Thus, all CMP entity beans are each broken up into two classes: the super-class, which you write and which
contains the entity bean data logic; and the subclass, which the container generates and which contains the
persistence logic. These two classes achieve a clean separation of entity bean logic and persistent
54 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
representation. The actual entity bean is a combination of the superclass and the subclass. This is shown in the
figure on the previous page.
2.2 CMP Entity Beans have no Declared Fields
Another issue with CMP is that the container might have additional fields or logic that are part of your
persistent representation but are container-specific. As a bean developer, you should be oblivious to this
information.
Since every container has its own proprietary way of dealing with your persistent representation, your persistent
fields are kept in the subclass, not the superclass. This is another paradigm shift with container-managed
persistent entity beans: You don’t declare any persistent fields in your bean.
For example, take a look at the following snippet of code from a BMP bank account entity bean class.

// BMP
public class AccountBean implements EntityBean {
public String accountID; // PK
public String ownerName;
public double balance;
...methods...
}
With CMP, the fields are not present. Rather, the container generates your persistent fields in the subclass. For
example, the following subclass might be generated from the container tools:
// CMP Subclass
public class AccountBeanSubClass extends AccountBean {
public String accountID; // PK
public String ownerName;
public double balance;
...methods...
}
2. 3 CMP Get/Set methods are defined in the Subclass
With CMP, the get/set methods would appear in the subclass, since that is where the fields exist and thus the
only place they can be accessed. Here is what the container-generated subclass looks like.
// CMP subclass
public class AccountBeanSubClass extends AccountBean {
public String accountID; // PK
public String ownerName;
public double balance;
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
...other methods...
}
So what does the superclass look like? First, realize that the superclass cannot possibly implement the get/set
methods because it doesn’t have access to the fields. However, the superclass does need to call those get/set
methods. For example, let’s say you have a shopping cart entity bean that contains a subtotal field and a taxes
field on the contents in the shopping cart. One useful method you might want to write is a getTotal() method,
which returns the subtotal + taxes. That is more than just a simple get/set method and thus cannot be generated
automatically by the container in the subclass. Therefore you need to write that method in the superclass
yourself. But what would that getTotal() method look like? With BMP, it could look like this:
// BMP
public class CartBean implements EntityBean {

55 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
...
public float getTotal() {
return this.getSubtotal() + this.getTaxes();
}
...
}

This code works well with BMP because we can define the getSubtotal() and getTaxes() methods. But with
CMP, the simple get/set methods getSubtotal() and getTaxes() are defined in the subclass, so how can we access
those get/set methods? The answer is to declare your get/set methods as abstract methods in the superclass. An
abstract method is a method whose implementation is deferred to a subclass; yet by defining a method as
abstract you can call it from the superclass. For example, a CMP shopping cart bean would look like this:
// CMP superclass
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
}

The subclass for this bean is the subclass we showed earlier. As another example, a CMP account bean would
look like this:
// CMP superclass
public abstract class AccountBean implements EntityBean {
// no fields
// abstract get/set methods
public abstract String getOwnerName();
public abstract void setOwnerName(String ownerName);
// EJB required methods follow
}

2.4 CMP Entity Beans have an Abstract Persistence Schema


CMP Entity bean have an abstract persistent schema. The EJB container inspects the deployment descriptors to
figure out what to generate. This definition of how you’d like to be persisted is called your 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>
...
The cmp-field elements are your container-managed persistent fields. Each field is a persistent field that the
container will generate in the subclass. The names of these fields must match the names of your abstract get/set
methods, except the first letter is not capitalized. For example, if your abstract get/set methods are
56 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
getOwnerName() and setOwnerName() then your cmp-field should be called ownerName. The container derives
the types of these fields from the get/set methods as well.

2.5 CMP Entity Beans have a Query Language


To enable clients of your bean to find you, you must define finder methods. For example, in BMP you’d define
this method in your home interface:
public Collection findBigAccounts(int minimum);

With CMP, the container generates this JDBC for us. However, we need a way to tell the container how to
generate that JDBC, because the container can’t magically know what find big accounts means.
The solution to this challenge is the EJB Query Language (EJB-QL). EJB-QL is an object-oriented SQL-like
syntax for querying entity beans. It contains a SELECT clause, a FROM clause, and an optional WHERE
clause. You write the EJB-QL code in the deployment descriptor, and the container should be able to generate
the corresponding database logic (such as SQL), perhaps with some help from the container tools.
Here is an example of EJB-QL that finds all accounts:
SELECT OBJECT(a)
FROM Account AS a
WHERE a.accountID IS NOT NULL

If you are using a relational database, at deployment time and with the help of the container’s tools that you use,
the container will inspect this code and generate the appropriate JDBC code.

Here is another example that satisfies the findBigAccounts() home method:


SELECT OBJECT(a)
FROM Account AS a
WHERE a.balance > ?1

In the above code, ?1 means the first parameter passed in, which in this case is the variable minimum.

2.6 CMP Entity Beans can have ejbSelect() Methods


The final major difference between BMP and CMP entity beans is that CMP entity beans can have special
ejbSelect() methods. An ejbSelect() method is a query method (like a finder method) but is not directly exposed
to the client in the home interface or component interface. Rather, ejbSelect() is used internally within an entity
bean as a helper method to access a storage. ejbSelect() is useful when you have entity beans in relationships
with external data, such as other entity beans.
For example, in our bank account example from the previous chapter, we defined a method called
ejbHomeGetTotalBankValue(), which added up the total of all bank accounts in the bank table by performing a
SQL SELECT statement using JDBC. With CMP, you shouldn’t be writing this JDBC code—rather, the
container should generate it for you in an ejbSelect() method, and you should call that ejbSelect() method from
the ejbHomeGetTotalBankValue() method. You then tell the container how to write the ejbSelect() method just
like you do a finder method—by using the EJB Query Language (EJB QL).
For example, you might define the following method in your entity bean:
public abstract Collection ejbSelectAllAccountBalances()
throws FinderException;

public double ejbHomeGetTotalBankValue() throws Exception {


// Get a collection of bank account balances
Collection c = this.ejbSelectAllAccountBalances();

57 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
// Loop through collection and return sum
}

The ejbSelect() methods are not exposed to end clients via the remote interface or local interface. They must be
called from within your bean, either from a business method or a home business method.
The value of ejbSelect() methods are threefold:
 Select methods can perform fine-grained database operations that your bean needs, but that you do not want
to expose to end clients.
 Select methods can retrieve data from other entity beans that you have relationships with.
 Like finder methods, select methods can return entity beans. But select methods are more powerful because
they can also return container-managed fields, such as our example above—it returns a collection of double
values.

58 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
3. Container-Managed Persistence Example: A Product Line
Let’s see a quick demonstration of CMP in action, applied to the concept of a product line. If you work for a
product-based company, your company’s product line is the suite of products that your company offers. For
example, if you’re an appliance company, you might offer a dishwasher, a stove, and a dryer. If you’re a
computer hardware company, you might offer memory, hard disks, and processors. We’re going to model a
generic product as an entity bean that uses CMP.
The object model for our product line is detailed in the following figure.

ProductHome.java: Home Interface


1 package examples;
2 import javax.ejb.*;
3 import java.rmi.RemoteException;
4 import java.util.*;
5 public interface ProductHome extends EJBHome
6 {
7 Product create(String productID, String name, String description,
8 double basePrice) throws CreateException, RemoteException;
9 public Product findByPrimaryKey(ProductPK key)
10 throws FinderException, RemoteException;
11 public Collection findByName(String name)
12 throws FinderException, RemoteException;
13 public Collection findByDescription(String description)
14 throws FinderException, RemoteException;
15 public Collection findByBasePrice(double basePrice)
16 throws FinderException, RemoteException;
17 public Collection findExpensiveProducts(double minPrice)
18 throws FinderException, RemoteException;
19 public Collection findCheapProducts(double maxPrice)
20 throws FinderException, RemoteException;
21 public Collection findAllProducts()
22 throws FinderException, RemoteException;
23 }

59 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
Product.java: Remote Interface

1 package examples;
2 import javax.ejb.*;
3 import java.rmi.RemoteException;
4 public interface Product extends EJBObject
5 {
6 public String getName() throws RemoteException;
7 public void setName(String name) throws RemoteException;
8 public String getDescription() throws RemoteException;
9 public void setDescription(String description)
10 throws RemoteException;
11 public double getBasePrice() throws RemoteException;
12 public void setBasePrice(double price) throws RemoteException;
13 public String getProductID() throws RemoteException;
14 }

ProductBean.java: Product Bean Class

1 package examples;
2 import javax.ejb.*;
3 public abstract class ProductBean implements EntityBean
4 {
5 protected EntityContext ctx;
6 public ProductBean()
7 {
8 }
9 //business logic methods
10 public abstract String getName() ;
11 public abstract void setName(String name);
12 public abstract String getDescription() ;
13 public abstract void setDescription(String description) ;
14 public abstract double getBasePrice() ;
15 public abstract void setBasePrice(double price) ;
16 public abstract String getProductID() ;
17 public abstract void setProductID(String productID) ;

18 public void ejbActivate()


19 {
20 System.out.println("ejbActivate () called.");
21 }
22 public void ejbRemove()
23 {
24 System.out.println("ejbRemove() called.");
25 }
26 public void ejbPassivate()
27 {
28 System.out.println("ejbPassivate () called.");
29 }
30 public void ejbLoad()
31 {
32 System.out.println("ejbLoad() called.");
33 }

34 public void ejbStore()


35 {

60 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
36 System.out.println("ejbStore() called.");
37 }
38 public void setEntityContext(EntityContext ctx)
39 {
40 System.out.println("setEntityContext called");
41 this.ctx = ctx;
42 }
43 public void unsetEntityContext()
44 {
45 System.out.println("unsetEntityContext called");
46 this.ctx = null;
47 }
48 public void ejbPostCreate(String productID, String name,
49 String description, double basePrice)
50 {
51 System.out.println("ejbPostCreate() called.");
52 }
53 public ProductPK ejbCreate(String productID, String name,
54 String description, double basePrice) throws CreateException
55 {
56 System.out.println("ejbCreate() called.");
57 setProductID(productID);
58 setName(name);
59 setDescription(description);
59 setBasePrice(basePrice);
60 return new ProductPK(productID);
61 }
62 }

ProductPK.java: Primary Key Class


1 package examples;
2 import java.io.Serializable;
3 public class ProductPK implements Serializable
4 { public String productID;
5 public ProductPK(String id)
6 {
7 this.productID = id;
8 }
9 public ProductPK()
10 {
11 }
12 public String toString()
13 {
14 return productID;
15 }
16 public int hashCode()
17 {
18 return productID.hashCode();
19 }
20 public boolean equals(Object product)
21 {
22 return ((ProductPK)product).productID.equals(productID);
23 }
24 }

61 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
ProductClient.java: The EJB Client
1 import javax.ejb.*;
2 import javax.naming.*;
3 import java.rmi.*;
4 import javax.rmi.*;
5 import java.util.*;
6 import examples.*;
7 import javax.transaction.UserTransaction;
8 public class ProductClient
9 {
10 public static void main(String[] args) throws Exception
11 {
12 ProductHome pHome = null;
13 javax.transaction.UserTransaction userTran = null;
14 try
15 { Hashtable props = new Hashtable();
16 props.put(Context.INITIAL_CONTEXT_FACTORY,
17 "weblogic.jndi.WLInitialContextFactory");
18 props.put(Context.PROVIDER_URL, "t3://client:7001");
19 Context ic = new InitialContext(props);
20 NamingEnumeration ne = ic.list("javax.transaction");
21 while(ne.hasMore())
22 {
23 System.out.println(ne.next());
24 }
25 userTran = (javax.transaction.UserTransaction)
26 ic.lookup("javax.transaction.UserTransaction");
27 System.out.println("Before lookup");
28 Object o=null;
29 o = ic.lookup("ProductBean");
30 userTran.begin();
31 System.out.println("After lookup");
32 pHome = (ProductHome)
33 javax.rmi.PortableRemoteObject.narrow(o, ProductHome.class);
34 System.out.println("After creation1");
35 pHome.create("123-456-7890", "P5-350", "350 Mhz Pentium",200);
36 System.out.println("After creation1");
37 pHome.create("123-456-7892", "P5-400", "400 Mhz Pentium",300);
38 pHome.create("123-456-7893", "P5-450", "450 Mhz Pentium",400);
39 pHome.create("123-456-7894", "SD-64", "64 MB SDRAM",50);
40 pHome.create("123-456-7895", "SD-128", "128 MB SDRAM",100);
41 pHome.create("123-456-7896", "SD-256", "256 MB SDRAM",200);
42 System.out.println("After creation");
43 Iterator i = pHome.findByName("SD-64").iterator();
44 System.out.println("These products match the name SD-64:");
45 while(i.hasNext())
46 { Product prod = (Product) i.next();
47 System.out.println(prod.getDescription());
48 }
49 System.out.println("Finding all products that cost $200");
50 i = pHome.findByBasePrice(200).iterator();
51 while(i.hasNext())
52 { Product prod = (Product) i.next();
53 System.out.println(prod.getDescription());
54 }
55 }

56 catch(Exception e)
57 { System.out.println("Caught Exception......");
58 e.printStackTrace();
62 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
59 }
60 catch(Throwable e)
61 { e.printStackTrace();
62 }
63 finally
64 { //userTran.rollback();
65 userTran.commit();
66 if(true) return;
67 if(pHome != null)
68 System.out.println("Destroying products....");
69 if(pHome == null)
70 System.out.println("Not Destroying products....");
71 Iterator i = pHome.findAllProducts().iterator();
72 if(i == null)
73 System.out.println("Not Destroying products....");
74 while(i.hasNext())
75 { try
76 { Product prod = (Product) i.next();
77 if(prod.getProductID().startsWith("123"))
78 prod.remove();
79 }
80 catch(Exception e)
81 { System.out.println("error in deleting product: ");
82 e.printStackTrace();
83 }
84 }
85 }
86 } //end method
87 }

ejb-jar.xml: The J2EE specific deployment descriptor


1 <!DOCTYPE ejb-jar PUBLIC '-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans
2 2.0//EN' 'http://java.sun.com/dtd/ejb-jar_2_0.dtd'>
3 <!-- Generated XML! -->
4 <ejb-jar>
5 <enterprise-beans>
6 <entity>
7 <ejb-name>ProductBean</ejb-name>
8 <home>examples.ProductHome</home>
9 <remote>examples.Product</remote>
10 ejb-class>examples.ProductBean</ejb-class>
11 <persistence-type>Container</persistence-type>
12 <prim-key-class>examples.ProductPK</prim-key-class>
13 <reentrant>False</reentrant>
14 <abstract-schema-name>ProductBean</abstract-schema-name>
15 <cmp-field>
16 <field-name>name</field-name>
17 </cmp-field>
18 <cmp-field>
19 <field-name>description</field-name>
20 </cmp-field>
21 <cmp-field>
22 <field-name>basePrice</field-name>
23 </cmp-field>
24 <cmp-field>
25 <field-name>productID</field-name>
26 </cmp-field>
27 <resource-ref>
28 <res-ref-name>jdbc/JDBCPool</res-ref-name>

63 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
29 <res-type>javax.sql.DataSource</res-type>
30 <res-auth>Container</res-auth>
31 </resource-ref>
32 <query>
33 <query-method>
34 <method-name>findAllProducts</method-name>
35 <method-params>
36 </method-params>
37 </query-method>
38 <ejb-ql><![CDATA[SELECT OBJECT(o) FROM ProductBean AS o]]></ejb-ql>
39 </query>
40 <query>
41 <query-method>
42 <method-name>findByBasePrice</method-name>
43 <method-params>
44 <method-param>double</method-param>
45 </method-params>
46 </query-method>
47 <ejb-ql><![CDATA[SELECT OBJECT(o)FROM ProductBean AS o
48 where o.basePrice = ?1]]></ejb-ql>
49 </query>
50 <query>
51 <query-method>
52 <method-name>findByDescription</method-name>
53 <method-params>
54 <method-param>java.lang.String</method-param>
55 </method-params>
56 </query-method>
57 <ejb-ql><![CDATA[SELECT OBJECT(o) FROM ProductBean AS o
58 where o.description = ?1]]></ejb-ql>
59 </query>
60 <query>
61 <query-method>
62 <method-name>findByName</method-name>
63 <method-params>
64 <method-param>java.lang.String</method-param>
65 </method-params>
66 </query-method>
67 <ejb-ql><![CDATA[SELECT OBJECT(o) FROM ProductBean AS o
68 where o.name = ?1]]></ejb-ql>
69 </query>
70 <query>
71 <query-method>
72 <method-name>findCheapProducts</method-name>
73 <method-params>
74 <method-param>double</method-param>
75 </method-params>
76 </query-method>
77 <ejb-ql><![CDATA[SELECT OBJECT(o) FROM ProductBean AS o
78 where o.basePrice <= ?1]]></ejb-ql>
79 </query>

80 <query>
81 <query-method>
82 <method-name>findExpensiveProducts</method-name>
83 <method-params>
84 <method-param>double</method-param>
85 </method-params>
86 </query-method>

64 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
87 <ejb-ql><![CDATA[SELECT OBJECT(o) FROM ProductBean AS o
88 where o.basePrice > ?1]]></ejb-ql>
89 </query>
90 </entity>
91 </enterprise-beans>
92 <assembly-descriptor>
93 <container-transaction>
94 <method>
95 <ejb-name>ProductBean</ejb-name>
96 <method-name>*</method-name>
97 </method>
98 <trans-attribute>Required</trans-attribute>
99 </container-transaction>
100 </assembly-descriptor>
101 </ejb-jar>

weblogic-ejb-jar.xml: The container specific deployment descriptor


1 <!DOCTYPE weblogic-ejb-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 8.1.0
2 EJB//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd'>
3 <!-- Generated XML! -->
4 <weblogic-ejb-jar>
5 <weblogic-enterprise-bean>
6 <ejb-name>ProductBean</ejb-name>
7 <entity-descriptor>
8 <pool>
9 </pool>
10 <entity-cache>
11 </entity-cache>
12 <persistence>
13 <persistence-use>
14 <type-identifier>WebLogic_CMP_RDBMS</type-identifier>
15 <type-version>7.0</type-version>
16 <type-storage>META-INF/weblogic-cmp-rdbms-jar.xml</type-storage>
17 </persistence-use>
18 </persistence>
19 <entity-clustering>
20 </entity-clustering>
21 </entity-descriptor>
22 <transaction-descriptor>
23 </transaction-descriptor>
24 <reference-descriptor>
25 <resource-description>
26 <res-ref-name>jdbc/JDBCPool</res-ref-name>
27 <jndi-name>JDBCDS</jndi-name>
28 </resource-description>
29 </reference-descriptor>
30 <jndi-name>ProductBean</jndi-name>
31 </weblogic-enterprise-bean>
32 </weblogic-ejb-jar>

65 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
weblogic-cmp-rdbms-jar: The container specific deployment descriptor for CMP configuration
1 <!DOCTYPE weblogic-rdbms-jar PUBLIC '-//BEA Systems,Inc.//DTD WebLogic 8.1.0
2 EJB RDBMS Persistence//EN' 'http://www.bea.com/servers/wls810/dtd/weblogic-
3 rdbms20-persistence-810.dtd'>
4 <!-- Generated XML! -->
5 <weblogic-rdbms-jar>
6 <weblogic-rdbms-bean>
7 <ejb-name>ProductBean</ejb-name>
8 <data-source-name>JDBCDS</data-source-name>
9 <table-map>
10 <table-name>products</table-name>
11 <field-map>
12 <cmp-field>basePrice</cmp-field>
13 <dbms-column>basePrice</dbms-column>
14 </field-map>
15 <field-map>
16 <cmp-field>productID</cmp-field>
17 <dbms-column>productID</dbms-column>
18 </field-map>
19 <field-map>
20 <cmp-field>description</cmp-field>
21 <dbms-column>description</dbms-column>
22 </field-map>
23 <field-map>
24 <cmp-field>name</cmp-field>
25 <dbms-column>name</dbms-column>
26 </field-map>
27 </table-map>
28 </weblogic-rdbms-bean>
29 <create-default-dbms-tables>CreateOnly</create-default-dbms-tables>
30 </weblogic-rdbms-jar>

66 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
4. Transaction Handling
There are two ways of demarcating transactional boundaries:
1. Declarative Transactions/Container Managed Transactions
2. Programmatic Transactions
4.1 Declarative Transactions
A method may run inside a transaction based on the entries given in the deployment descriptor. The following
entry indicates that all the methods of bean must run inside container initiated transactions.
<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>
We can set same transaction type for all methods by using * form as used above:
<method-name> * </method-name>

It is also possible to specify different transaction types for different methods by providing separate entry for
each method. For each method entry will be of the form:
<method>
<ejb-name>Employee</ejb-name>
<method-name>m1</method-name>
<method-param>java.lang.String</method-param>
</method>
<trans-attribute>Required</trans-attribute>

4.1.1 EJB Transaction Attributes


The transaction attribute for Container-Managed Transactions can be any one of the following:
Required, RequiresNew, Supports, Mandatory, NotSupported, Never
The Effects of Transaction Attributes are summarized below:
Transaction Attribute Client’s Transaction Bean’s Transaction
Required none T2
T1 T1
RequiresNew none T2
T1 T2 (T1 is suspended till T2 completes)
Supports none none
T1 T1
Mandatory none error
T1 T1
NotSupported none none
T1 none (T1 is suspended)
Never none none
T1 error

67 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
4.2 Programmatic Transactions in EJB
Both declarative as well as programmatic transactions are handled by JTS (Java Transaction Service). The
services of JTS like beginning and ending transactions are availed using JTA (Java Transaction API). In case of
declarative transactions, it is the container which uses the services of JTS. In case of programmatic transactions,
it is the programmer who is responsible for availing services of JTS by using JTA.
The programmatic transactions can be further classified as:
1. Bean Initiated Transactions
2. Client Initiated Transactions

4.2.1 Java Transaction API (JTA)


The JTA consists of two interfaces:
1. javax.transaction.UserTransaction
2. javax.transaction.Status

The javax.transaction.UserTransaction interface allows you to programmatically control transactions. Here is


what the javax.transaction.UserTransaction interface looks like:
public interface javax.transaction.UserTransaction
{ public void begin();
public void commit();
public int getStatus();
public void rollback();
public void setRollbackOnly();
public void setTransactionTimeout(int);
}

The implementation of this interface is provided by the container. We need to get the reference of this object
before using the JTA API. The container is responsible for creating instance of object of type UserTransaction
and binding it in the JNDI from where it can be looked up and can be used to communicate with the JTS.
The javax.transaction.Status interface defines the constants used to represent various states 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;
public static final int STATUS_PREPARING;
public static final int STATUS_PREPARED;
public static final int STATUS_COMMITTING;
public static final int STATUS_COMMITTED;
public static final int STATUS_ROLLING_BACK;
public static final int STATUS_ROLLEDBACK;
public static final int STATUS_UNKNOWN;
}

4.2.2 Programmatic Transaction initiated from inside a bean

The following code segments illustrates how we can handle transactions from within the bean:
EntityContext ctx;
.
.
.
javax.transaction.UserTransaction userTran = null;
|
68 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T
|
userTran = ctx.getUserTransaction();
userTran.begin(); //begin transaction

balance += amt;
.
.
userTran.commit(); //or userTran.rollback() to end the transaction
4.2.3 Programmatic Transaction initiated from Client
The client normally runs on a different JVM, so it needs to lookup the UserTransaction object before using JTA
API. The following code segment illustrates how an EJB client can handle the transactions:
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,
”weblogic.jndi.WLInitialContextFactory”);
env.put(Context.PROVIDER_URL, “t3://client:7001”);
Context ctx = new InitialContext(env);
userTran = (javax.transaction.UserTransaction)
ctx.lookup("javax.transaction.UserTransaction");
.
.
userTran.begin(); //to begin transaction
.
.
userTran.commit(); //or userTran.rollback() to end transaction

4.3 Transactional Isolation Levels


There are four Transaction Isolation levels:
1. READ UNCOMMITTED
It may lead to dirty, un-repeatable and phantom read problems. It gives no isolation guarantee but provides
highest performance. (No locks)
2. READ COMMITTED
Solves only dirty read problem. It does not solve unrepeatable and phantom read problems.
3. REPEATABLE READ
Solves dirty read and unrepeatable read problems. It does not solve phantom read problem. It is achieved by
putting lock on a set of rows so that you cannot modify them. No other concurrent transaction will be
allowed to modify the rows.
4. SERIALIZABLE
It solves all the problems but gives lowest performance. It may be achieved by using table level lock or
database level lock. There are two approaches for achieving this level of isolation:
• Pessimistic Concurrency Control, and
• Optimistic Concurrency Control
4.3.1 Isolation and EJB
We can achieve desired level of isolation in case of bean managed transactions by calling the following method
of java.sql.Connection interface:
void setTransactionIsolation(int isolationLevel)
There is no standard way of setting isolation level in case of container managed transactions.

69 | S u m i t A g r a w a l | J A V A A r c h i t e c t | M C C R e t a i l C O E | H C L T

You might also like