Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Session Beans Entity beans provide an object-oriented model that makes it easier for developers to create, modify, and delete data from the database.

Similar presentations


Presentation on theme: "1 Session Beans Entity beans provide an object-oriented model that makes it easier for developers to create, modify, and delete data from the database."— Presentation transcript:

1 1 Session Beans Entity beans provide an object-oriented model that makes it easier for developers to create, modify, and delete data from the database. They allow developers to be more productive by encouraging reuse, thus reducing development costs. For example, once a bean has been defined to represent a concept like a ship, that bean can be reused throughout a business system without redefining, recoding, or retesting the business logic and data access. Session beans fill the gaps left by entity beans. They are useful for describing interactions between other beans (taskflow) and for implementing particular tasks. Unlike entity beans, session beans do not represent data in the database, but they can access data. This means that we can use session beans to read, update, and insert data in a business process.

2 2 Session Beans When do you use an entity bean and when do you use a session bean? As a rule of thumb, an entity bean should provide a safe and consistent interface to a set of shared data that defines a concept. This data may be updated frequently. Session beans access data that spans concepts, is not shared, and is usually read- only. Session beans contain business logic and entity beans model persistent data. In addition to accessing data directly, session beans can represent taskflow. Taskflow refers to all the steps required to accomplish a particular task, such as booking passage on a ship or renting a video. Session beans frequently manage the interactions among entity beans, describing how they work together to accomplish a specific task.

3 3 Session Beans The relationship between session beans and entity beans is like the relationship between a script for a play and the actors that perform the play. Actors are pointless without a script; they may represent something, but they can't tell a story. Session beans are divided into two basic types: stateless and stateful. A stateless session bean is a collection of related services, each represented by a method; the bean maintains no state from one method invocation to the next. When you invoke a method on a stateless session bean, it executes the method and returns the result without knowing or caring what other requests have gone before or might follow.

4 4 Session Beans Think of a stateless session bean as a set of procedures or batch programs that execute a request based on some parameters and return a result. A stateful session bean is an extension of the client application. It performs tasks on behalf of a client and maintains state related to that client. This state is called conversational state because it represents a continuing conversation between the stateful session bean and the client. Methods invoked on a stateful session bean can write and read data to and from this conversational state, which is shared among all methods in the bean. Stateful session beans tend to be specific to one scenario. They represent logic that might have been captured in the client application of a two-tier system.

5 5 Session Beans Stateless session beans have longer lives because they do not retain any conversational state and are not dedicated to one client. As soon as a stateless session bean has finished a method invocation, it can be reassigned to service a new client. Whether they are stateful or stateless, session beans are not persistent, like entity beans are. In other words, session beans don't represent persistent data and are not saved to the database.

6 6 The Stateless Session Bean A stateless session bean is very efficient and relatively easy to develop. A session bean can be swapped freely between EJB objects because it isn't dedicated to one client and doesn't maintain any conversational state. As soon as it is finished servicing a method invocation it can be swapped to another EJB object. Because it does not maintain conversational state, a stateless session bean does not require passivation or activation, further reducing the overhead of swapping. In short, stateless session beans are lightweight and fast.

7 7 The Stateless Session Bean Stateless session beans can be used for report generation, batch processing, or some stateless services such as validating credit cards. Another good application might be a StockQuote EJB that returns a stock's current price. Any activity that can be accomplished in one method call is a good candidate for the high-performance stateless session bean.

8 8 The ProcessPayment EJB The next section develops a complete definition of the TravelAgent EJB, including the logic of the bookPassage( ) method. At this point, however, we are primarily interested in the ProcessPayment EJB, which is a stateless bean the TravelAgent EJB uses to charge the customer for the price of the cruise. Because many different systems charge customers for services, we've encapsulated the logic for charging customers in its own bean. Payments are recorded in a special database table called PAYMENT.

9 9 The ProcessPayment EJB The PAYMENT data is batch-processed for accounting purposes and is not normally used outside of accounting. In other words, the data is only inserted by Titan's system; it is not read, updated, or deleted. Because the process of making a charge can be completed in one method, and because the data is not updated frequently and is not shared, we will use a stateless session bean for processing payments. Several different forms of payment can be used: credit card, check, and cash. We will model these payment forms in our stateless ProcessPayment EJB.

10 10 The database table: PAYMENT The ProcessPayment EJB accesses an existing table in Titan's system, called the PAYMENT table. In your database, create a table called PAYMENT, with this definition: CREATE TABLE PAYMENT ( customer_id INTEGER, amount DECIMAL(8,2), type CHAR(10), check_bar_code CHAR(50), check_number INTEGER, credit_number CHAR(20), credit_exp_date DATE )

11 11 The business interface: ProcessPayment A stateless session bean has one or more business interfaces. The business interface for ProcessPayment obviously needs a byCredit( ) method because the TravelAgent EJB uses it. We can also identify two other methods that we'll need: byCash( ) for customers paying cash and byCheck( ) for customers paying with a personal check. A business interface can be a remote or local interface, but not both. Remote business interfaces are able to receive method invocations from networked clients. Local interfaces are available only within the same JVM as the session bean. Invoking on a local interface does not copy the parameters or return value. Because of this, local interfaces are said to follow what is termed call-by-reference semantics.

12 12 The business interface: ProcessPayment Since the TravelAgent EJB will be in the same deployment, the ProcessPayment EJB should provide a local interface so that invocations on ProcessPayment are efficient. The ProcessPayment EJB also has remote clients, so we'll provide a remote business interface as well. To make our design a little bit cleaner, we will have these interfaces extend a base interface called com.titan.processpayment.ProcessPayment : package com.titan.processpayment; import com.titan.domain.*; public interface ProcessPayment { public boolean byCheck(Customer customer, CheckDO check, double amount) throws PaymentException; public boolean byCash(Customer customer, double amount) throws PaymentException; public boolean byCredit(Customer customer, CreditCardDO card, double amount) throws PaymentException; }

13 13 The business interface: ProcessPayment The EJB specification allows you to define a common base class for our remote and local interfaces if they share the same methods. Next, let's specify both the remote and local interfaces: package com.titan.processpayment; import javax.ejb.Remote; @Remote public interface ProcessPaymentRemote extends ProcessPayment { } package com.titan.processpayment; import javax.ejb.Local; @Local public interface ProcessPaymentLocal extends ProcessPayment{ }

14 14 The business interface: ProcessPayment The ProcessPaymentRemote and ProcessPaymentLocal interfaces extend the base ProcessPayment interface so that they do not have to duplicate the method definitions. ProcessPaymentRemote is identified as a remote interface by the @javax.ejb.Remote annotation and ProcessPaymentLocal by the @javax.ejb.Local annotation.

15 15 Entities as parameters Each method of the ProcessPayment EJB's business interface takes a Customer entity bean as a parameter. Because entity beans are plain Java objects, they can be serialized across the network as plain Java objects as long as they implement java.io.Serializable or Externalizable. This is important because the ProcessPayment EJB accesses the internal state of the Customer entity. If every call to the Customer's get methods went over a remote interface (as is required in the EJB 2.1 specification), the ProcessPayment EJB would be very inefficient, because network calls are expensive. This is yet another example of the simplicity of the EJB 3.0 specification. In EJB 2.1, because entities were first-class components, one had to write parallel value object classes if one wanted to pass around the state of an entity instead of accessing it through the old remote interface model.

16 16 Domain objects: the CreditCardDO and CheckDO classes Domain objects: the CreditCardDO and CheckDO classes The ProcessPayment EJB's business interface uses two classes that are particularly interesting, CreditCardDO and CheckDO: /* CreditCardDO.java */ package com.titan.processpayment; import java.util.Date; public class CreditCardDO implements java.io.Serializable { final static public String MASTER_CARD = "MASTER_CARD"; final static public String VISA = "VISA"; final static public String AMERICAN_EXPRESS = "AMERICAN_EXPRESS"; final static public String DISCOVER = "DISCOVER"; final static public String DINERS_CARD = "DINERS_CLUB_CARD";

17 17 Domain objects: the CreditCardDO and CheckDO classes Domain objects: the CreditCardDO and CheckDO classes public String number; public Date expiration; public String type; public CreditCardDO (String nmbr, Date exp, String typ) { number = nmbr; expiration = exp; type = typ; } /* CheckDO.java */ package com.titan.processpayment; public class CheckDO implements java.io.Serializable { public String checkBarCode; public int checkNumber; public CheckDO(String barCode, int number) { checkBarCode = barCode; checkNumber = number; }

18 18 Domain objects: the CreditCardDO and CheckDO classes Domain objects: the CreditCardDO and CheckDO classes CreditCardDO and CheckDO are domain objects. They are simply serializable Java classes, not enterprise beans; they provide a convenient mechanism for transporting related data. CreditCardDO, for example, collects all the credit card data together in one class, making it easier to pass the information across the network as well as making our interfaces a little cleaner.

19 19 An application exception: PaymentException It is important to understand what exceptions you should use, and when you should use them. Exceptions such as javax.naming.NamingException and java.sql.SQLException are thrown by other Java subsystems and have nothing to do with the business process an EJB is supposed to be modeling. Checked exceptions (non-Runtime Exceptions), by default, do not cause a transaction rollback. Instead of throwing these types of exceptions directly, you should catch them in a try/catch block and throw a more appropriate exception. A common practice is to wrap these checked exceptions in a javax.ejb.EJBException, as these types of subsystem errors are unrecoverable.

20 20 An application exception: PaymentException EJBException is unchecked (it extends java.lang.RuntimeException ), so you won't get a compile error if you don't catch it. A PaymentException describes a specific business problem that is possibly recoverable. This makes it an application exception. The EJB container treats any exception that does not extend RuntimeException as an application exception. Here is the definition of PaymentException: package com.titan.processpayment; public class PaymentException extends java.lang.Exception { public PaymentException( ) { super( ); } public PaymentException(String msg) { super(msg); }

21 21 The bean class: ProcessPaymentBean The ProcessPayment EJB models a specific business process, so it is an excellent candidate for a stateless session bean. This bean really represents a set of independent operations - another indication that it is a good candidate for a stateless session bean. Here is the definition of the ProcessPaymentBean class: package com.titan.processpayment; import com.titan.domain.*; import java.sql.*; import javax.ejb.*; import javax.annotation.Resource; import javax.sql.DataSource; import javax.ejb.EJBException;

22 22 The bean class: ProcessPaymentBean @Stateless public class ProcessPaymentBean implements ProcessPaymentRemote, ProcessPaymentLocal { final public static String CASH = "CASH"; final public static String CREDIT = "CREDIT"; final public static String CHECK = "CHECK"; @Resource(mappedName="titanDB") DataSource dataSource; @Resource(name="min") int minCheckNumber; public boolean byCash(Customer customer, double amount) throws PaymentException { return process(customer.getId( ), amount, CASH, null, -1, null, null); } public boolean byCheck(Customer customer, CheckDO check, double amount) throws PaymentException { if (check.checkNumber > minCheckNumber) { return process(customer.getId( ), amount, CHECK, check.checkBarCode, check.checkNumber, null, null); } else { throw new PaymentException("Check number is too low. Must be at least "+minCheckNumber); }

23 23 The bean class: ProcessPaymentBean public boolean byCredit(Customer customer, CreditCardDO card, double amount) throws PaymentException { if (card.expiration.before(new java.util.Date( ))) { throw new PaymentException("Expiration date has passed"); } else { return process(customer.getId( ), amount, CREDIT, null, -1, card.number, new java.sql.Date(card.expiration.getTime( ))); } } private boolean process(int customerID, double amount, String type, String checkBarCode, int checkNumber, String creditNumber, java.sql.Date creditExpDate) throws PaymentException { Connection con = null; PreparedStatement ps = null; try { con = dataSource.getConnection( ); ps = con.prepareStatement ("INSERT INTO payment (customer_id, amount, type,"+ "check_bar_code,check_number,credit_number,"+ "credit_exp_date) VALUES (?,?,?,?,?,?,?)");

24 24 The bean class: ProcessPaymentBean ps.setInt(1,customerID); ps.setDouble(2,amount); ps.setString(3,type); ps.setString(4,checkBarCode); ps.setInt(5,checkNumber); ps.setString(6,creditNumber); ps.setDate(7,creditExpDate); int retVal = ps.executeUpdate( ); if (retVal!=1) { throw new EJBException("Payment insert failed"); } return true; } catch(SQLException sql) { throw new EJBException(sql); } finally { try { if (ps != null) ps.close( ); if (con!= null) con.close( ); } catch(SQLException se) { se.printStackTrace( ); }

25 25 The bean class: ProcessPaymentBean The bean class is annotated with the @javax.ejb.Stateless annotation to identify that it is a stateless session bean: Package javax.ejb; @Target(TYPE) @Retention(RUNTIME) public @interface Stateless { String name( ) default ""; } The three payment methods use the private helper method process( ), which does the work of adding the payment to the database. This strategy reduces the possibility of programmer error and makes the bean easier to maintain. The process( ) method does not use entity beans but simply inserts the payment information directly into the PAYMENT table using JDBC. The JDBC connection is obtained from the datasource field of the bean class.

26 26 Accessing environment properties (injection) The datasource and minCheckNumber fields are examples of session bean fields that are initialized by the EJB's environment. Each EJB container has its own internal registry where it stores configuration values and references to external resources and services. This registry is called the Enterprise Naming Context (ENC). If you look at the declaration of these member variables, you will see that they are annotated with @javax.annotation.Resource. This tells the EJB container that when an instance of the bean class is instantiated, those fields must be initialized with values in the container's ENC.

27 27 Accessing environment properties (injection) For minCheckNumber, the @Resource annotation identifies a named value within the ENC that may be used to initialize the field externally. This named value can be configured using the EJB's XML deployment descriptor: <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = " http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0"> ProcessPaymentBean min java.lang.Integer 250 The XML populates the EJB's ENC under the name min with a value of 250.

28 28 The XML Deployment Descriptor Here is a deployment descriptor that provides a complete annotation-alternative definition of the ProcessPayment EJB: <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0"> ProcessPaymentBean com.titan.processpayment.ProcessPaymentRemote com.titan.processpayment.ProcessPaymentLocal com.titan.processpayment.ProcessPaymentBean Stateless theDatasource javax.sql.DataSource Container titandb com.titan.processpayment.ProcessPaymentBean dataSource

29 29 The XML Deployment Descriptor min java.lang.Integer 250 com.titan.processpayment.ProcessPaymentBean minCheckNumber The XML deployment descriptor schema also supports partial XML definitions. For example, if you just wanted to configure the minCheckNumber field in XML, you wouldn't have to declare every piece of metadata about the EJB:

30 30 The XML Deployment Descriptor ProcessPaymentBean min java.lang.Integer 250

31 31 SessionContext The javax.ejb.SessionContext interface provides a view into the EJB container's environment. The SessionContext object can be used as the bean instance's interface to the EJB container to obtain information about the context of the method invocation call and to provide quick access to various EJB services. A session bean can obtain a reference to its SessionContext by using the @Resource annotation: @Stateless public class ProcessPaymentBean implements ProcessPaymentLocal { @Resource SessionContext ctx;... }

32 32 SessionContext SessionContext allows you to obtain information such as the current user that is invoking on the EJB or to look up entries within the EJB's ENC. Let's look at the javax.ejb.SessionContext interface: public interface javax.ejb.SessionContext extends javax.ejb.EJBContext { EJBLocalObject getEJBLocalObject( ) throws IllegalStateException EJBObject getEJBObject( ) throws IllegalStateException; MessageContext getMessageContext( ) throws IllegalStateException; getBusinessObject(Class businessInterface) throws IllegalStateException; Class getInvokedBusinessInterface( ); } The getEJBObject( ) and getEJBLocalObject( ) methods are obsolete and will throw an exception if invoked on. They are objects that are specific to the EJB 2.1 style of defining EJBs.

33 33 SessionContext The SessionContext.getBusinessObject( ) method returns a reference to the current EJB that can be invoked on by other clients. This reference is the EJB equivalent to Java's this pointer. The getBusinessObject( ) method allows the bean instance to get its own EJB object reference, which it can then pass to other beans. Here is an example: @Stateless public class A_Bean implements A_BeanRemote { @Resource private SessionContext context; public void someMethod( ) { B_BeanRemote b =... // Get a remote reference to B_Bean. A_BeanRemote mySelf = getBusinessObject(A_BeanRemote.class); b.aMethod( mySelf ); }... } It is illegal for a bean instance to pass a this reference to another bean; instead, it passes its remote or local EJB object reference, which the bean instance gets from its SessionContext.

34 34 EJBContext SessionContext extends the javax.ejb.EJBContext class. EJBContext defines several methods that provide useful information to a bean at runtime. Here is the definition of the EJBContext interface: package javax.ejb; public interface EJBContext { public Object lookup(String name); // EJB 2.1 only: TimerService public TimerService getTimerService( ) throws java.lang.IllegalStateException; // security methods public java.security.Principal getCallerPrincipal( ); public boolean isCallerInRole(java.lang.String roleName);

35 35 EJBContext // transaction methods public javax.transaction.UserTransaction getUserTransaction( ) throws java.lang.IllegalStateException; public boolean getRollbackOnly( ) throws java.lang.IllegalStateException; public void setRollbackOnly( ) throws java.lang.IllegalStateException; // deprecated and obsolete methods public java.security.Identity getCallerIdentity( ); public boolean isCallerInRole(java.security.Identity role); public java.util.Properties getEnvironment( ); public EJBHome getEJBHome( ) java.lang.IllegalStateException; public EJBLocalHome getEJBLocalHome( ) java.lang.IllegalStateException; }

36 36 The Life Cycle of a Stateless Session Bean The life cycle of a stateless session bean is very simple. It has only two states: Does Not Exist and Method-Ready Pool. Stateless session bean life cycle

37 37 The Does Not Exist State When a bean is in the Does Not Exist state, it is not an instance in the memory of the system. In other words, it has not been instantiated yet.

38 38 The Method-Ready Pool Stateless bean instances enter the Method- Ready Pool as the container needs them. When the EJB server is first started, it may create a number of stateless bean instances and enter them into the Method-Ready Pool. (The actual behavior of the server depends on the implementation.) When the number of stateless instances servicing client requests is insufficient, more can be created and added to the pool.

39 39 Transitioning to the Method-Ready Pool When an instance transitions from the Does Not Exist state to the Method-Ready Pool, three operations are performed on it. First, the bean instance is instantiated by invoking the Class.newInstance( ) method on the stateless bean class. Second, the container injects any resources that the bean's metadata has requested via an injection annotation or XML deployment descriptor. Finally, the EJB container will post a post-construction event. The bean class can register for this event by annotating a method with @javax.annotation.PostConstruct. This annotated method is called by the container after the bean is instantiated. The callback method can be of any name, but it must return void, have no parameters, and throw no checked exceptions. The bean class may define only one @PostConstruct method (but it is not required to do so).

40 40 Transitioning to the Method-Ready Pool @Stateless public class MyBean implements MyLocal { @PostConstruct public void myInit( ) {} Alternatively, you can declare your @PostConstruct method in the EJB's XML deployment descriptor: MyBean myInit

41 41 Life in the Method-Ready Pool Once an instance is in the Method-Ready Pool, it is ready to service client requests. When a client invokes a business method on an EJB object, the method call is delegated to any available instance in the Method-Ready Pool. While the instance is executing the request, it is unavailable for use by other EJB objects. Once the instance has finished, it is immediately available to any EJB object that needs it. Stateless session instances are dedicated to an EJB object only for the duration of a single method call.

42 42 Transitioning out of the Method-Ready Pool: the death of a stateless bean instance Bean instances leave the Method-Ready Pool for the Does Not Exist state when the server no longer needs them - that is, when the server decides to reduce the total size of the Method-Ready Pool by evicting one or more instances from memory. The process begins when a PreDestroy event on the bean is triggered. The bean class can register for this event by annotating a method with @javax.annotation.PreDestroy. The container calls this annotated method when the PreDestroy event is fired. This callback method can be of any name, but it must return void, have no parameters, and throw no checked exceptions. The bean class may define only one @PreDestroy method (but it is not required to do so).

43 43 The Stateful Session Bean Each stateful session bean is dedicated to one client for the life of the bean instance; it acts on behalf of that client as its agent. Stateful session beans are not swapped among EJB objects nor are they kept in an instance pool, like stateless session bean instances are. Once a stateful session bean is instantiated and assigned to an EJB object, it is dedicated to that EJB object for its entire life cycle. Stateful session beans maintain conversational state, which means that the instance variables of the bean class can maintain data specific to the client between method invocations.

44 44 The Stateful Session Bean Stateful session beans allow you to encapsulate some of the business logic and conversational state of a client and move it to the server. Moving this logic to the server thins the client application and makes the system as a whole easier to manage. The stateful session bean acts as an agent for the client, managing processes or taskflow to accomplish a set of tasks; it manages the interactions of other beans in addition to direct data access over several operations to accomplish a complex set of tasks.

45 45 Getting Set Up for the TravelAgent EJB The TravelAgent EJB will use the Cabin, Cruise, Reservation, and Customer entity beans that we have devloped earlier. It will coordinate the interaction of these entity beans to book a passenger on a cruise. We'll modify the Reservation entity so that it can be created with all of its relationships identified right away. In other words, we will define another constructor in addition to a default constructor: public class Reservation { public Reservation( ) {} public Reservation(Customer customer, Cruise cruise, Cabin cabin, double price, Date dateBooked) { setAmountPaid(price); setDate(dateBooked); setCruise(cruise);

46 46 Getting Set Up for the TravelAgent EJB Set cabins = new HashSet( ); cabins.add(cabin); this.setCabins(cabins); Set customers = new HashSet( ); customers.add(customer); this.setCustomers(customers); } Creating this constructor will allow us to avoid calling all of those setter methods within our TravelAgent EJB code and will make it less cluttered.

47 47 The TravelAgent EJB The TravelAgent EJB, which we have already seen, is a stateful session bean that encapsulates the process of making a reservation on a cruise. We will develop this bean further to demonstrate how stateful session beans can be used as taskflow objects. We won't develop a local interface for the TravelAgent EJB, partly because it is designed to be used by remote clients (and therefore doesn't require local component interfaces), and partly because the rules for developing local interfaces for stateful session beans are the same as those for stateless session beans.

48 48 The remote interface: TravelAgent Here's the modified TravelAgentRemote interface: package com.titan.travelagent; import com.titan.processpayment.CreditCardDO; import javax.ejb.Remote; import com.titan.domain.Customer; @Remote public interface TravelAgentRemote { public Customer findOrCreateCustomer(String first, String last); public void updateAddress(Address addr); public void setCruiseID(int cruise); public void setCabinID(int cabin); public TicketDO bookPassage(CreditCardDO card, double price) throws IncompleteConversationalState; }

49 49 The remote interface: TravelAgent The IncompleteConversationalState exception indicates that the TravelAgent EJB did not have enough information to process the booking. Here's the IncompleteConversationalState class: package com.titan.travelagent; public class IncompleteConversationalState extends java.lang.Exception { public IncompleteConversationalState( ){super( ); } public IncompleteConversationalState(String msg) { super(msg); }

50 50 Domain objects: the TicketDO class Like the CreditCardDO and CheckDO classes used in the ProcessPayment EJB, the TicketDO class is defined as a pass-by-value object. One could argue that a ticket should be the Reservation entity bean, since it is a plain Java object and could be serialized back to the client. However, determining how a business object is used can also dictate whether it should be a bean or simply a class. Because the Reservation entity bean references a lot of interrelated entities, the number of objects serialized back to the client could become quite large, and thus very inefficient. With the TicketDO object, you can pull together the exact information you want to send back to the client.

51 51 Domain objects: the TicketDO class The constructor for TicketDO uses the entities from which it pulls the data: package com.titan.travelagent; import com.titan.domain.Cruise; import com.titan.domain.Cabin; import com.titan.domain.Customer; public class TicketDO implements java.io.Serializable { public int customerID; public int cruiseID; public int cabinID; public double price; public String description;

52 52 Domain objects: the TicketDO class public TicketDO(Customer customer, Cruise cruise, Cabin cabin, double price) { description = customer.getFirstName( )+ " " + customer.getLastName( ) + " has been booked for the " + cruise.getName( ) + " cruise on ship " + cruise.getShip( ).getName( ) + ".\n" + " Your accommodations include " + cabin.getName( ) + " a " + cabin.getBedCount( ) + " bed cabin on deck level " + cabin.getDeckLevel( ) + ".\n Total charge = " + price; customerID = customer.getId( ); cruiseID = cruise.getId( ); cabinID = cabin.getId( ); this.price = price; } public String toString( ) { return description; }

53 53 The bean class: TravelAgentBean We can now implement all of the behavior expressed in the new remote interface for the TravelAgent EJB. Here is a partial definition of the new TravelAgentBean class: package com.titan.travelagent; import com.titan.processpayment.*; import com.titan.domain.*; import javax.ejb.*; import javax.persistence.*; import javax.annotation.EJB; import java.util.Date; @Stateful public class TravelAgentBean implements TravelAgentRemote { @PersistenceContext(unitName="titan") private EntityManager entityManager; @EJB private ProcessPaymentLocal processPayment;

54 54 The bean class: TravelAgentBean private Customer customer; private Cruise cruise; private Cabin cabin; public Customer findOrCreateCustomer(String first, String last) { try { Query q = entityManager.createQuery("from Customer c where c.firstName = :first and c.lastName = :last"); q.setParameter("first", first); q.setParameter("last", last); this.customer = (Customer)q.getSingleResult( ); } catch (NoResultException notFound) { this.customer = new Customer( ); this.customer.setFirstName(first); this.customer.setLastName(last); entityManager.persist(this.customer); } return this.customer; } public void updateAddress(Address addr) { this.customer.setAddress(addr); this.customer = entityManager.merge(customer); }

55 55 The bean class: TravelAgentBean public void setCabinID(int cabinID) { this.cabin = entityManager.find(Cabin.class, cabinID); if (cabin == null) throw new NoResultException("Cabin not found"); } public void setCruiseID(int cruiseID) { this.cruise = entityManager.find(Cruise.class, cruiseID); if (cruise == null) throw new NoResultException("Cruise not found"); } @Remove public TicketDO bookPassage(CreditCardDO card, double price) throws IncompleteConversationalState { if (customer == null || cruise == null || cabin == null) { throw new IncompleteConversationalState( ); }

56 56 The bean class: TravelAgentBean try { Reservation reservation = new Reservation( customer, cruise, cabin, price, new Date( )); entityManager.persist(reservation); processPayment.byCredit(customer, card, price); TicketDO ticket = new TicketDO(customer, cruise, cabin, price); return ticket; } catch(Exception e) { throw new EJBException(e); }

57 57 The bookPassage( ) method The last point of interest in our bean definition is the bookPassage( ) method. This method uses the conversational state accumulated by the findOrCreateCustomer( ), setCabinID( ), and setCruiseID( ) methods to process a reservation for a customer. Here's how the bookPassage( ) method is defined: @Remove public TicketDO bookPassage(CreditCardDO card, double price) throws IncompleteConversationalState { if (customer == null || cruise == null || cabin == null) { throw new IncompleteConversationalState( ); } try { Reservation reservation = new Reservation( customer, cruise, cabin, price, new Date( )); entityManager.persist(reservation); process.byCredit(customer, card, price); TicketDO ticket = new TicketDO(customer, cruise, cabin, price); return ticket; } catch(Exception e) { throw new EJBException(e); }

58 58 The bookPassage( ) method This method demonstrates the taskflow concept. It uses several beans, including the ProcessPayment EJB and the Reservation, Customer, Cabin, and Cruise entities, to accomplish one task: booking a customer on a cruise. Deceptively simple, this method encapsulates several interactions that ordinarily might have been performed on the client. For the price of one bookPassage( ) call from the client, the TravelAgent EJB performs the following operations, in this order:

59 59 The bookPassage( ) method Creates a new Reservation object Persists the new Reservation object with the entity manager service Charges the customer's credit card using the ProcessPayment EJB Generates a new TicketDO with all the pertinent information describing the customer's purchase Notice that the bookPassage( ) method is annotated with the @javax.ejb.Remove annotation. The @Remove annotation tells the EJB container that when the method completes, the client no longer needs the session. After the bookPassage( ) method completes, the EJB container removes the session from the EJB container.

60 60 The XML Deployment Descriptor Here is a deployment descriptor that provides a complete annotation-alternative definition of the TravelAgent EJB: <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd" version="3.0"> TravelAgentBean com.titan.travelagent.TravelAgentRemote com.titan.travelagent.TravelAgentBean Stateful ejb/PaymentProcessor Session com.titan.processpayment.ProcessPaymentLocal

61 61 The XML Deployment Descriptor com.titan.travelagent.TravelAgentBean processPayment persistence/titan titan com.titan.travelagent.TravelAgentBean entityManager

62 62 The Life Cycle of a Stateful Session Bean The biggest difference between the stateful session bean and the other bean types is that stateful session beans do not use instance pooling. Stateful session beans are dedicated to one client for their entire lives, so swapping or pooling of instances isn't possible. Some vendors use pooling with stateful session beans, but that is a proprietary implementation and should not affect the specified life cycle of the stateful session bean. The life cycle of a stateful session bean has three states: Does Not Exist, Method-Ready, and Passivated. This sounds a lot like a stateless session bean, but the Method-Ready state is significantly different from the Method- Ready Pool of stateless beans.

63 63 The Life Cycle of a Stateful Session Bean Stateful session bean life cycle

64 64 The Does Not Exist State A stateful bean instance in the Does Not Exist state has not been instantiated yet. It doesn't exist in the system's memory.

65 65 The Method-Ready State The Method-Ready state is the state in which the bean instance can service requests from its clients. This section explores the instance's transition into and out of the Method-Ready state.

66 66 Transitioning into the Method-Ready state When a client invokes the first method on the stateful session bean reference, the bean's life cycle begins. The container invokes newInstance( ) on the bean class, creating a new instance of the bean. Next, the container injects any dependencies into the bean instance. At this point, the bean instance is assigned to the client referencing it. Finally, just like stateless session beans, the container invokes any @PostConstruct callbacks if there is a method in the bean class that has this annotation applied. Once @PostConstruct has completed, the container continues with the actual method call.

67 67 Life in the Method-Ready state While in the Method-Ready state, the bean instance is free to receive method invocations from the client, which may involve controlling the taskflow of other beans or accessing the database directly. During this time, the bean can maintain conversational state and open resources in its instance variables.

68 68 Transitioning out of the Method-Ready state Bean instances leave the Method-Ready state to enter either the Passivated state or the Does Not Exist state. Depending on how the client uses the stateful bean, the EJB container's load, and the passivation algorithm used by the vendor, a bean instance may be passivated (and activated) several times in its life, or not at all. If the bean is removed, it enters the Does Not Exist state. A client application can remove a bean by invoking a business interface method annotated as @Remove.

69 69 The Passivated State During the lifetime of a stateful session bean, there may be periods of inactivity when the bean instance is not servicing methods from the client. To conserve resources, the container can passivate the bean instance by preserving its conversational state and evicting the bean instance from memory. A bean's conversational state may consist of primitive values, objects that are serializable, and the following special types:

70 70 The Passivated State javax.ejb.SessionContext javax.jta.UserTransaction (bean transaction interface) javax.naming.Context (only when it references the JNDI ENC) javax.persistence.EntityManager javax.persistence.EntityManagerFactory References to managed resource factories (e.g., javax.sql.DataSource ) References to other EJBs The activation of a bean instance follows the rules of Java serialization, regardless of how the bean's state was actually stored.

71 71 System exceptions Whenever a system exception is thrown by a bean method, the container invalidates the EJB object and destroys the bean instance. The bean instance moves directly to the Does Not Exist state, and any @PreDestroy call methods are not invoked.

72 72 Nested Stateful Session Beans Stateful session beans behave in interesting ways when you inject other stateful session beans within them. When you inject a stateful session bean into an EJB with the @EJB annotation, a session is created for that injected instance: @Stateful public class ShoppingCartBean implements ShoppingCart{ @EJB AnotherStatefulLocal another; @Remove void checkout {} } When a stateful bean reference is injected into another stateful session bean, the containing bean owns the injected session.

73 73 Nested Stateful Session Beans This means that when the containing bean is created, a unique session is created for the injected reference. When the containing bean is removed, the contained stateful bean is also removed. In the ShoppingCartBean example, an AnotherStatefulLocal session is created for the another member variable when an instance of it is created. When the checkout( ) method is called, another's stateful session is also removed. This feature of the specification allows you to cleanly aggregate conversational business processes without having to worry about managing the life cycle of the contained stateful sessions.


Download ppt "1 Session Beans Entity beans provide an object-oriented model that makes it easier for developers to create, modify, and delete data from the database."

Similar presentations


Ads by Google