Step 8 - EJB2
Step 8 - EJB2
Step 8 - EJB2
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.
The three tier architecture evolved to solve the problems faced in 2-tier architecture.
Second tier
or
Application Logic
Middle tier
(Business Layer)
Third Tier
(Data Layer)
XML
DB Flat Files
Document
Container/Component Contract
Application Application
Other Component Component Declarative
Container Services
Services
Application
Component
Deployment Deployment
Descriptor Descriptor
Deployment
Descriptor
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.
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.
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.
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.
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.
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;
}
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
public class HelloBean implements SessionBean {
private SessionContext sessionContext;
// Bean Rule - matching home's create(). See the return type, here is void
public void ejbCreate() {
System.out.println("In the ejbCreate() method");
}
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
// Be good n use RMI remote object narrowing as required by the EJB specification
HelloHome ejbHome = (HelloHome) javax.rmi.PortableRemoteObject.narrow(obj, HelloHome.class);
}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
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.
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.
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
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();
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.
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
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 –
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.
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");
2. Now using this factory we can create a connection with Queue or Topic
QueueConnection connection = connectionFactory.createQueueConnection();
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.
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 {
sender.close();
session.close();
}
}
HelloWorld – Receiver.java
public class Receiver implements MessageListener {
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
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.
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");
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.
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.
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;
}
}
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.
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:
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.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 {}
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.
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 }
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 }
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 }
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 }
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
}
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.
In the above code, ?1 means the first parameter passed in, which in this case is the variable minimum.
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.
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 }
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) ;
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 }
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 }
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>
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>
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
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;
}
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
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