Session Beans l l Entity beans provide an
Session Beans l l 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 1 process.
Session Beans l l l 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 readonly. 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. 2
Session Beans l l 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. 3
Session Beans l l 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. 4
Session Beans l l 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. 5
The Stateless Session Bean l l 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. 6
The Stateless Session Bean l l l 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 Stock. Quote 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. 7
The Process. Payment EJB l l The next section develops a complete definition of the Travel. Agent EJB, including the logic of the book. Passage( ) method. At this point, however, we are primarily interested in the Process. Payment EJB, which is a stateless bean the Travel. Agent 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. 8
The Process. Payment EJB l l l 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 Process. Payment EJB. 9
The database table: PAYMENT l l The Process. Payment 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 ) 10
The business interface: Process. Payment l l l A stateless session bean has one or more business interfaces. The business interface for Process. Payment obviously needs a by. Credit( ) method because the Travel. Agent EJB uses it. We can also identify two other methods that we'll need: by. Cash( ) for customers paying cash and by. Check( ) 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. 11
The business interface: Process. Payment l l Since the Travel. Agent EJB will be in the same deployment, the Process. Payment EJB should provide a local interface so that invocations on Process. Payment are efficient. The Process. Payment 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. Process. Payment : package com. titan. processpayment; import com. titan. domain. *; public interface Process. Payment { public boolean by. Check(Customer customer, Check. DO check, double amount) throws Payment. Exception; public boolean by. Cash(Customer customer, double amount) throws Payment. Exception; public boolean by. Credit(Customer customer, Credit. Card. DO card, double amount) throws Payment. Exception; } 12
The business interface: Process. Payment l l 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 Process. Payment. Remote extends Process. Payment { } package com. titan. processpayment; import javax. ejb. Local; @Local public interface Process. Payment. Local extends Process. Payment{ } 13
The business interface: Process. Payment l l The Process. Payment. Remote and Process. Payment. Local interfaces extend the base Process. Payment interface so that they do not have to duplicate the method definitions. Process. Payment. Remote is identified as a remote interface by the @javax. ejb. Remote annotation and Process. Payment. Local by the @javax. ejb. Local annotation. 14
Entities as parameters l l l Each method of the Process. Payment 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 Process. Payment 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 Process. Payment 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. 15
Domain objects: the Credit. Card. DO and Check. DO classes l The Process. Payment EJB's business interface uses two classes that are particularly interesting, Credit. Card. DO and Check. DO: /* Credit. Card. DO. java */ package com. titan. processpayment; import java. util. Date; public class Credit. Card. DO 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"; 16
Domain objects: the Credit. Card. DO and Check. DO classes public String number; public Date expiration; public String type; public Credit. Card. DO (String nmbr, Date exp, String typ) { number = nmbr; expiration = exp; type = typ; } } /* Check. DO. java */ package com. titan. processpayment; public class Check. DO implements java. io. Serializable { public String check. Bar. Code; public int check. Number; public Check. DO(String bar. Code, int number) { check. Bar. Code = bar. Code; check. Number = number; } } 17
Domain objects: the Credit. Card. DO and Check. DO classes l l l Credit. Card. DO and Check. DO are domain objects. They are simply serializable Java classes, not enterprise beans; they provide a convenient mechanism for transporting related data. Credit. Card. DO, 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. 18
An application exception: Payment. Exception l l l It is important to understand what exceptions you should use, and when you should use them. Exceptions such as javax. naming. Naming. Exception 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. 19
An application exception: Payment. Exception l l l EJBException is unchecked (it extends java. lang. Runtime. Exception ), so you won't get a compile error if you don't catch it. A Payment. Exception 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 Runtime. Exception as an application exception. Here is the definition of Payment. Exception: package com. titan. processpayment; public class Payment. Exception extends java. lang. Exception { public Payment. Exception( ) { super( ); } public Payment. Exception(String msg) { super(msg); } } 20
The bean class: Process. Payment. Bean l l The Process. Payment 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 Process. Payment. Bean class: package com. titan. processpayment; import com. titan. domain. *; import java. sql. *; import javax. ejb. *; import javax. annotation. Resource; import javax. sql. Data. Source; import javax. ejb. EJBException; 21
The bean class: Process. Payment. Bean @Stateless public class Process. Payment. Bean implements Process. Payment. Remote, Process. Payment. Local { final public static String CASH = "CASH"; final public static String CREDIT = "CREDIT"; final public static String CHECK = "CHECK"; @Resource(mapped. Name="titan. DB") Data. Source data. Source; @Resource(name="min") int min. Check. Number; public boolean by. Cash(Customer customer, double amount) throws Payment. Exception { return process(customer. get. Id( ), amount, CASH, null, -1, null); } public boolean by. Check(Customer customer, Check. DO check, double amount) throws Payment. Exception { if (check. Number > min. Check. Number) { return process(customer. get. Id( ), amount, CHECK, check. Bar. Code, check. Number, null); } else { throw new Payment. Exception("Check number is too low. Must be at least "+min. Check. Number); } } 22
The bean class: Process. Payment. Bean public boolean by. Credit(Customer customer, Credit. Card. DO card, double amount) throws Payment. Exception { if (card. expiration. before(new java. util. Date( ))) { throw new Payment. Exception("Expiration date has passed"); } else { return process(customer. get. Id( ), amount, CREDIT, null, -1, card. number, new java. sql. Date(card. expiration. get. Time( ))); } } private boolean process(int customer. ID, double amount, String type, String check. Bar. Code, int check. Number, String credit. Number, java. sql. Date credit. Exp. Date) throws Payment. Exception { Connection con = null; Prepared. Statement ps = null; try { con = data. Source. get. Connection( ); ps = con. prepare. Statement ("INSERT INTO payment (customer_id, amount, type, "+ "check_bar_code, check_number, credit_number, "+ "credit_exp_date) VALUES (? , ? , ? , ? )"); 23
The bean class: Process. Payment. Bean ps. set. Int(1, customer. ID); ps. set. Double(2, amount); ps. set. String(3, type); ps. set. String(4, check. Bar. Code); ps. set. Int(5, check. Number); ps. set. String(6, credit. Number); ps. set. Date(7, credit. Exp. Date); int ret. Val = ps. execute. Update( ); if (ret. Val!=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. print. Stack. Trace( ); } } 24
The bean class: Process. Payment. Bean l 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 ""; } l l 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. 25
Accessing environment properties (injection) l l l The datasource and min. Check. Number 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. 26
Accessing environment properties (injection) l For min. Check. Number, 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. w 3. org/2001/XMLSchema-instance" xsi: schema. Location = " http: //java. sun. com/xml/ns/javaee/ejb-jar_3_0. xsd" version="3. 0"> <enterprise-beans> <session> <ejb-name>Process. Payment. Bean</ejb-name> <env-entry-name>min </env-entry-name> <env-entry-type>java. lang. Integer</env-entry-type> <env-entry-value>250</env-entry-value> </env-entry> </session> </enterprise-beans> </ejb-jar> l The XML populates the EJB's ENC under the name min with a value of 250. 27
The XML Deployment Descriptor l Here is a deployment descriptor that provides a complete annotation-alternative definition of the Process. Payment EJB: <? xml version="1. 0"? > <ejb-jar xmlns="http: //java. sun. com/xml/ns/javaee" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" xsi: schema. Location= "http: //java. sun. com/xml/ns/javaee/ejb-jar_3_0. xsd" version="3. 0"> <enterprise-beans> <session> <ejb-name>Process. Payment. Bean</ejb-name> <remote>com. titan. processpayment. Process. Payment. Remote</remote> <local>com. titan. processpayment. Process. Payment. Local</local> <ejb-class>com. titan. processpayment. Process. Payment. Bean</ejb-class> <session-type>Stateless</session-type> <resource-ref> <res-ref-name>the. Datasource</res-ref-name> <res-type>javax. sql. Data. Source</res-type> <res-auth>Container</res-auth> <mapped-name>titandb</mapped-name> <injection-target-class> com. titan. processpayment. Process. Payment. Bean </injection-target-class> <injection-target-name>data. Source</injection-target-name> </injection-target> </resource-ref> 28
The XML Deployment Descriptor <env-entry> <env-entry-name>min</env-entry-name> <env-entry-type>java. lang. Integer</env-entry-type> <env-entry-value>250</env-entry-value> <injection-target-class> com. titan. processpayment. Process. Payment. Bean </injection-target-class> <injection-target-name>min. Check. Number </injection-target-name> </injection-target> </env-entry> </session> </enterprise-beans> </ejb-jar> l The XML deployment descriptor schema also supports partial XML definitions. For example, if you just wanted to configure the min. Check. Number field in XML, you wouldn't have to declare every piece of metadata about the EJB: 29
The XML Deployment Descriptor <ejb-jar> <session> <ejb-name>Process. Payment. Bean</ejb-name> <env-entry-name>min</env-entry-name> <env-entry-type>java. lang. Integer</env-entry-type> <env-entry-value>250</env-entry-value> </env-entry> </session> </ejb-jar> 30
Session. Context l l l The javax. ejb. Session. Context interface provides a view into the EJB container's environment. The Session. Context 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 Session. Context by using the @Resource annotation: @Stateless public class Process. Payment. Bean implements Process. Payment. Local { @Resource Session. Context ctx; . . . } 31
Session. Context l l Session. Context 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. Session. Context interface: public interface javax. ejb. Session. Context extends javax. ejb. EJBContext { EJBLocal. Object get. EJBLocal. Object( ) throws Illegal. State. Exception EJBObject get. EJBObject( ) throws Illegal. State. Exception; Message. Context get. Message. Context( ) throws Illegal. State. Exception; <T> get. Business. Object(Class<T> business. Interface) throws Illegal. State. Exception; Class get. Invoked. Business. Interface( ); } l l The get. EJBObject( ) and get. EJBLocal. Object( ) 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. 32
Session. Context l l The Session. Context. get. Business. Object( ) 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 get. Business. Object( ) 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_Bean. Remote { @Resource private Session. Context context; public void some. Method( ) { B_Bean. Remote b =. . . // Get a remote reference to B_Bean. A_Bean. Remote my. Self = get. Business. Object(A_Bean. Remote. class); b. a. Method( my. Self ); }. . . } l 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 Session. Context. 33
EJBContext l l Session. Context 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: Timer. Service public Timer. Service get. Timer. Service( ) throws java. lang. Illegal. State. Exception; // security methods public java. security. Principal get. Caller. Principal( ); public boolean is. Caller. In. Role(java. lang. String role. Name); 34
EJBContext // transaction methods public javax. transaction. User. Transaction get. User. Transaction( ) throws java. lang. Illegal. State. Exception; public boolean get. Rollback. Only( ) throws java. lang. Illegal. State. Exception; public void set. Rollback. Only( ) throws java. lang. Illegal. State. Exception; // deprecated and obsolete methods public java. security. Identity get. Caller. Identity( ); public boolean is. Caller. In. Role(java. security. Identity role); public java. util. Properties get. Environment( ); public EJBHome get. EJBHome( ) java. lang. Illegal. State. Exception; public EJBLocal. Home get. EJBLocal. Home( ) java. lang. Illegal. State. Exception; } 35
The Life Cycle of a Stateless Session Bean l 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 36
The Does Not Exist State l l 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. 37
The Method-Ready Pool l 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. 38
Transitioning to the Method-Ready Pool l l 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. new. Instance( ) 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. Post. Construct. 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 @Post. Construct method (but it is not required to do so). 39
Transitioning to the Method-Ready Pool @Stateless public class My. Bean implements My. Local { @Post. Construct public void my. Init( ) {} l Alternatively, you can declare your @Post. Construct method in the EJB's XML deployment descriptor: <ejb-jar> <enterprise-beans> <session> <ejb-name>My. Bean</ejb-name> <post-construct> <lifecycle-callback-method>my. Init</lifecycle-callback-method> </post-construct> </session> </enterprise-beans> </ejb-jar> 40
Life in the Method-Ready Pool l l 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. 41
Transitioning out of the Method-Ready Pool: the death of a stateless bean instance l l 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 Pre. Destroy event on the bean is triggered. The bean class can register for this event by annotating a method with @javax. annotation. Pre. Destroy. The container calls this annotated method when the Pre. Destroy 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 @Pre. Destroy method (but it is not required to do so). 42
The Stateful Session Bean l l 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. 43
The Stateful Session Bean l l l 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. 44
Getting Set Up for the Travel. Agent EJB l The Travel. Agent 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 date. Booked) { set. Amount. Paid(price); set. Date(date. Booked); set. Cruise(cruise); 45
Getting Set Up for the Travel. Agent EJB Set cabins = new Hash. Set( ); cabins. add(cabin); this. set. Cabins(cabins); Set customers = new Hash. Set( ); customers. add(customer); this. set. Customers(customers); } l Creating this constructor will allow us to avoid calling all of those setter methods within our Travel. Agent EJB code and will make it less cluttered. 46
The Travel. Agent EJB l l l The Travel. Agent 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 Travel. Agent 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. 47
The remote interface: Travel. Agent l l Here's the modified Travel. Agent. Remote interface: package com. titan. travelagent; import com. titan. processpayment. Credit. Card. DO; import javax. ejb. Remote; import com. titan. domain. Customer; @Remote public interface Travel. Agent. Remote { public Customer find. Or. Create. Customer(String first, String last); public void update. Address(Address addr); public void set. Cruise. ID(int cruise); public void set. Cabin. ID(int cabin); public Ticket. DO book. Passage(Credit. Card. DO card, double price) throws Incomplete. Conversational. State; } 48
The remote interface: Travel. Agent l The Incomplete. Conversational. State exception indicates that the Travel. Agent EJB did not have enough information to process the booking. Here's the Incomplete. Conversational. State class: package com. titan. travelagent; public class Incomplete. Conversational. State extends java. lang. Exception { public Incomplete. Conversational. State( ){super( ); } public Incomplete. Conversational. State(String msg) { super(msg); } } 49
Domain objects: the Ticket. DO class l l l Like the Credit. Card. DO and Check. DO classes used in the Process. Payment EJB, the Ticket. DO 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 Ticket. DO object, you can pull together the exact information you want to send back to the client. 50
Domain objects: the Ticket. DO class l The constructor for Ticket. DO 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 Ticket. DO implements java. io. Serializable { public int customer. ID; public int cruise. ID; public int cabin. ID; public double price; public String description; 51
Domain objects: the Ticket. DO class public Ticket. DO(Customer customer, Cruise cruise, Cabin cabin, double price) { description = customer. get. First. Name( )+ " " + customer. get. Last. Name( ) + " has been booked for the " + cruise. get. Name( ) + " cruise on ship " + cruise. get. Ship( ). get. Name( ) + ". n" + " Your accommodations include " + cabin. get. Name( ) + " a " + cabin. get. Bed. Count( ) + " bed cabin on deck level " + cabin. get. Deck. Level( ) + ". n Total charge = " + price; customer. ID = customer. get. Id( ); cruise. ID = cruise. get. Id( ); cabin. ID = cabin. get. Id( ); this. price = price; } public String to. String( ) { return description; } } 52
The bean class: Travel. Agent. Bean l We can now implement all of the behavior expressed in the new remote interface for the Travel. Agent EJB. Here is a partial definition of the new Travel. Agent. Bean class: package com. titan. travelagent; import import com. titan. processpayment. *; com. titan. domain. *; javax. ejb. *; javax. persistence. *; javax. annotation. EJB; java. util. Date; @Stateful public class Travel. Agent. Bean implements Travel. Agent. Remote { @Persistence. Context(unit. Name="titan") private Entity. Manager entity. Manager; @EJB private Process. Payment. Local process. Payment; 53
The bean class: Travel. Agent. Bean private Customer customer; private Cruise cruise; private Cabin cabin; public Customer find. Or. Create. Customer(String first, String last) { try { Query q = entity. Manager. create. Query("from Customer c where c. first. Name = : first and c. last. Name = : last"); q. set. Parameter("first", first); q. set. Parameter("last", last); this. customer = (Customer)q. get. Single. Result( ); } catch (No. Result. Exception not. Found) { this. customer = new Customer( ); this. customer. set. First. Name(first); this. customer. set. Last. Name(last); entity. Manager. persist(this. customer); } return this. customer; } public void update. Address(Address addr) { this. customer. set. Address(addr); this. customer = entity. Manager. merge(customer); } 54
The bean class: Travel. Agent. Bean public void set. Cabin. ID(int cabin. ID) { this. cabin = entity. Manager. find(Cabin. class, cabin. ID); if (cabin == null) throw new No. Result. Exception("Cabin not found"); } public void set. Cruise. ID(int cruise. ID) { this. cruise = entity. Manager. find(Cruise. class, cruise. ID); if (cruise == null) throw new No. Result. Exception("Cruise not found"); } @Remove public Ticket. DO book. Passage(Credit. Card. DO card, double price) throws Incomplete. Conversational. State { if (customer == null || cruise == null || cabin == null) { throw new Incomplete. Conversational. State( ); } 55
The bean class: Travel. Agent. Bean try { Reservation reservation = new Reservation( customer, cruise, cabin, price, new Date( )); entity. Manager. persist(reservation); process. Payment. by. Credit(customer, card, price); Ticket. DO ticket = new Ticket. DO(customer, cruise, cabin, price); return ticket; } catch(Exception e) { throw new EJBException(e); } } } 56
The book. Passage( ) method l The last point of interest in our bean definition is the book. Passage( ) method. This method uses the conversational state accumulated by the find. Or. Create. Customer( ), set. Cabin. ID( ), and set. Cruise. ID( ) methods to process a reservation for a customer. Here's how the book. Passage( ) method is defined: @Remove public Ticket. DO book. Passage(Credit. Card. DO card, double price) throws Incomplete. Conversational. State { if (customer == null || cruise == null || cabin == null) { throw new Incomplete. Conversational. State( ); } try { Reservation reservation = new Reservation( customer, cruise, cabin, price, new Date( )); entity. Manager. persist(reservation); process. by. Credit(customer, card, price); Ticket. DO ticket = new Ticket. DO(customer, cruise, cabin, price); return ticket; } catch(Exception e) { throw new EJBException(e); } 57 }
The book. Passage( ) method l l This method demonstrates the taskflow concept. It uses several beans, including the Process. Payment 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 book. Passage( ) call from the client, the Travel. Agent EJB performs the following operations, in this order: 58
The book. Passage( ) method l l l Creates a new Reservation object Persists the new Reservation object with the entity manager service Charges the customer's credit card using the Process. Payment EJB Generates a new Ticket. DO with all the pertinent information describing the customer's purchase Notice that the book. Passage( ) 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 book. Passage( ) method completes, the EJB container removes the session from the EJB container. 59
The XML Deployment Descriptor l Here is a deployment descriptor that provides a complete annotation-alternative definition of the Travel. Agent EJB: <? xml version="1. 0"? > <ejb-jar xmlns="http: //java. sun. com/xml/ns/javaee" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" xsi: schema. Location="http: //java. sun. com/xml/ns/javaee/ejb-jar_3_0. xsd" version="3. 0"> <enterprise-beans> <session> <ejb-name>Travel. Agent. Bean</ejb-name> <remote>com. titan. travelagent. Travel. Agent. Remote</remote> <ejb-class>com. titan. travelagent. Travel. Agent. Bean</ejb-class> <session-type>Stateful </session-type> <ejb-local-ref> <ejb-ref-name>ejb/Payment. Processor</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <local>com. titan. processpayment. Process. Payment. Local</local> 60
The XML Deployment Descriptor <injection-target> <injection-target-class> com. titan. travelagent. Travel. Agent. Bean </injection-target-class> <injection-target-name>process. Payment </injection-target-name> </injection-target> </ejb-local-ref> <persistence-context-ref-name> persistence/titan </persistence-context-ref-name> <persistence-unit-name>titan</persistence-unit-name> <injection-target-class> com. titan. travelagent. Travel. Agent. Bean </injection-target-class> <injection-target-name>entity. Manager</injection-target-name> </injection-target> </persistence-context-ref> </session> </enterprise-beans> </ejb-jar> 61
The Life Cycle of a Stateful Session Bean l l l 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. 62
The Life Cycle of a Stateful Session Bean Stateful session bean life cycle 63
The Does Not Exist State A stateful bean instance in the Does Not Exist state has not been instantiated yet. l It doesn't exist in the system's memory. l 64
The Method-Ready State The Method-Ready state is the state in which the bean instance can service requests from its clients. l This section explores the instance's transition into and out of the Method-Ready state. l 65
Transitioning into the Method-Ready state l l l When a client invokes the first method on the stateful session bean reference, the bean's life cycle begins. The container invokes new. Instance( ) 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 @Post. Construct callbacks if there is a method in the bean class that has this annotation applied. Once @Post. Construct has completed, the container continues with the actual method call. 66
Life in the Method-Ready state l l 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. 67
Transitioning out of the Method-Ready state l l l 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. 68
The Passivated State l l l 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: 69
The Passivated State l l l l javax. ejb. Session. Context javax. jta. User. Transaction (bean transaction interface) javax. naming. Context (only when it references the JNDI ENC) javax. persistence. Entity. Manager. Factory References to managed resource factories (e. g. , javax. sql. Data. Source ) 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. 70
System exceptions l l 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 @Pre. Destroy call methods are not invoked. 71
Nested Stateful Session Beans l 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 Shopping. Cart. Bean implements Shopping. Cart{ @EJB Another. Stateful. Local another; @Remove void checkout {} } l When a stateful bean reference is injected into another stateful session bean, the containing bean owns the injected session. 72
Nested Stateful Session Beans l l 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 Shopping. Cart. Bean example, an Another. Stateful. Local 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. 73
- Slides: 73