Implementing a Stateless Session Bean

Implementing a Session bean involves providing an implementation for the methods of the javax.ejb.SessionBean, corresponding methods for each method in the home interface, and a method for each method in the remote interface.

Implementing javax.ejb.SessionBean

The implementation of the methods of the SessionBean interface is often boilerplate. The setSessionContext() method usually just saves the supplied SessionContext object:

private SessionContext ctx;
public void setSessionContext(SessionContext ctx) {
    this.ctx = ctx;
}

Although ejbRemove() method is part of the SessionBean interface, you'll learn about its implementation in the next section. As already noted, for a stateless Session bean, the ejbActivate() and ejbPassivate() methods should have a null implementation:

public void ejbActivate() { }
public void ejbPassivate() { }

Implementing the Home Interface Methods

The home interface has a single method create(). The ejbCreate() method in the bean corresponds to this method. It makes sense to look up JNDI references in the ejbCreate() method and store them in instance variables. This is shown in Listing 5.2.

Listing 5.2. AgencyBean.ejbCreate() Method
 1: private DataSource dataSource;
 2: private String name = "";
 3: public void ejbCreate () throws CreateException {
 4:     InitialContext ic = null;
 5:     try {
 6:         ic = new InitialContext();
 7:         dataSource = (DataSource)ic.lookup("java:comp/env/jdbc/Agency");
 8:     }
 9:     catch (NamingException ex) {
10:         error("Error connecting to java:comp/env/jdbc/Agency:",ex);
11:         return;
12:     }
13:     try {
14:         name = (String)ic.lookup("java:comp/env/AgencyName");
15:     }
16:     catch (NamingException ex) {
17:         error("Error looking up java:comp/env/AgencyName:",ex);
18:     }
19: }

Tip

On Day 18, “Patterns,” you will learn about a design pattern that simplifies JNDI lookups. It can also speed up your beans; some EJB containers are not particularly efficient at obtaining references from within JNDI.


In this case, the ejbCreate() method makes two lookups from JNDI; the first is to obtain a DataSource (you will see how this is used shortly) and the other is to obtain environment configuration information—that is, the name of the agency—from the deployment descriptor. You will learn about the deployment descriptor in the following section.

Incidentally, this is a good place to note that stateless Session bean does not mean that the bean has no state; just that it has no state that is specific to any given client. In the case of the Agency bean, it caches a DataSource and its name in instance variables.

The home interface inherits a remove(Object o) from EJBHome. This corresponds to the ejbRemove() method of the bean. The implementation is pretty simple; it should just reset state:

public void ejbRemove(){
    dataSource = null;
}

Note

The ejbRemove() method is mandated by the EJB specification in three different ways! It appears in the SessionBean interface, and it is required as the method corresponding to the home method of remove(Object) (inherited from javax.ejb.EJBHome) and is also required as the method corresponding to the remote method of remove() (inherited from javax.ejb.EJBObject). It is covered here because it fits best along side the coverage of ejbCreate().


Implementing the Remote Interface Methods

The remaining methods correspond to the business methods defined in the remote interface. The Agency session bean manipulates the data in the Applicant, Customer, Location, and Skill tables, providing methods to return all the data in a table, to insert a new item, or to delete an existing item. When deleting rows, rows in dependent tables are also removed.

The methods that manipulate the database all require a java.sql.Connection to submit SQL to the database. In regular “fat client” applications, the idiom is to create a database connection at application startup and to close the connection only when the user quits the application. This idiom exists because making database connections is expensive in performance terms. When writing EJBs, however, the idiom is the precise opposite. You should obtain the database connection just before it is needed, and close it as soon as your processing is complete. In other words, “acquire late, release early.” This is because the EJB container has already made the database connections and holds them in a pool. When your bean obtains its connection, it is simply being “leased” one from the pool for a period of time. When the connection is “closed,” in reality it is simply returned back to the pool to be used again.

The getLocations() method shows this principle clearly, as shown in Listing 5.3.

Listing 5.3. AgencyBean.getLocations() Method
 1: public Collection getLocations() {
 2:     Connection con = null;
 3:     PreparedStatement stmt = null;
 4:     ResultSet rs = null;
 5:     try {
 6:         con = dataSource.getConnection();
 7:         stmt = con.prepareStatement("SELECT name FROM Location");
 8:         rs = stmt.executeQuery();
 9:
10:         Collection col = new TreeSet();
11:         while (rs.next()) {
12:             col.add(rs.getString(1));
13:         }
14:
15:         return col;
16:     }
17:     catch (SQLException e) {
18:         error("Error getting Location list",e);
19:     }
20:     finally {
21:         closeConnection(con, stmt, rs);
22:     }
23:     return null;
24: }
25: private void closeConnection (Connection con,
26:              PreparedStatement stmt, ResultSet rslt) {
27:    if (rslt != null) {
28:       try {
29:           rslt.close();
30:       }
31:       catch (SQLException e) {}
32:   }
33:   if (stmt != null) {
34:       try {
35:           stmt.close();
36:       }
37:       catch (SQLException e) {}
38:   }
39:   if (con != null) {
40:       try {
41:           con.close();
42:       }
43:       catch (SQLException e) {}
44:   }
45: }
						

In this method, you can see the DataSource object obtained in the ejbCreate() method in use. The Connection object is obtained from this DataSource object. Another advantage of this approach is that the user and password information does not need to be embedded within the code; rather, it is set up by the deployer who configures the DataSource using vendor-specific tools. As you remember from Day 2, “The J2EE Platform and Roles,” in the J2EE RI, the DataSource object is configured using the j2eeadmin tool.

The other business methods all access the database in a similar manner.

Exceptions

Your bean needs to be able to indicate when it hits an exception. The EJB specification lays out certain rules as to the types of exceptions your bean can throw, because the client does not call your bean directly. For remote clients, there is also the possibility of network problems.

The EJB specification categorizes exceptions as either application exceptions or system exceptions. These correspond quite closely to the regular Java categories of checked exceptions and runtime exceptions.

Figure 5.5 shows the exceptions in the javax.ejb package, indicating which are application and which are system exceptions.

Figure 5.5. Exceptions are either system exceptions or application exceptions.


So, what do these categorizations mean? If a bean throws an application exception, the EJB container will propagate this back to the application client. As you shall see on Day 8, “Transactions and Persistence,” any ongoing transaction is not terminated by an application exception. In other words, the semantics of an application exception are pretty similar to a checked exception; generally, the client can recover if desired.

However, if a bean throws a system exception, that indicates a severe problem that will not be recoverable by the client. For example, if the bean has been incorrectly deployed such that the database connection fails, there is very little that the client can do about it.

In such a case, the EJB container will take steps to terminate any ongoing transaction because it is unlikely to complete. Moreover, the EJB container will discard the bean instance that threw the exception. In other words, there is no need to code any clean up logic in your bean after having thrown a system exception.

Although all runtime exceptions are classified as EJB system exceptions, the javax.ejb.EJBException is a RuntimeException provided for your use. This class allows the underlying cause to be wrapped through one of its constructors. The error() helper method in AgencyBean does precisely this:

private void error (String msg, Exception ex) {
    String s = "AgencyBean: "+msg + "
" + ex;
    System.out.println(s);
    throw new EJBException(s,ex);
}

In Figure 5.5, you can see that there is one checked exception, namely java.rmi.RemoteException, that is classified as an EJB system exception rather than as an EJB application exception. Your bean code should never throw this exception; instead, it is reserved for the EJB container itself to throw. If your bean has hit a system exception, it should throw an EJBException rather than RemoteException.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.137.67