The information in this chapter is not exhaustive; however, it includes the information you need to develop basic enterprise beans. For information on developing more complicated enterprise beans, consult a commercially available book on enterprise bean development. The example enterprise beans discussed in this chapter and the example Java applications and servlets that use them are described in Information about the examples described in the documentation.
This chapter describes the requirements for building each of the major components of an enterprise bean. If you do not intend to use one of the commercially available integrated development environments (IDE), such as IBM's VisualAge for Java, you must build each of these components manually (by using tools in the Java Development Kit and WebSphere). Manually developing enterprise beans is much more difficult and error-prone than developing them in an IDE. Therefore, it is strongly recommended that you choose an IDE with which you are comfortable.
This section examines the development of entity beans with CMP. While much of the information in this section also applies to entity beans with BMP, there are some major differences between the two types. For information on the tasks required to develop an entity bean with BMP, see Developing entity beans with BMP.
Every entity bean must contain the following basic parts:
By convention, the enterprise bean class is named NameBean, where Name is the name you assign to the enterprise bean. The enterprise bean class for the example Account enterprise bean is named AccountBean. Every entity bean class with CMP must meet the following requirements:
The enterprise bean class can implement the enterprise bean's remote interface, but this is not recommended. If the enterprise bean class implements the remote interface, it is possible to inadvertently pass the this variable as a method argument.
An enterprise bean class cannot implement two different interfaces if the methods in the interfaces have the same name, even if the methods have different signatures, due to the Java-IDL mapping specification. Errors can occur when the enterprise bean is deployed.
Figure 18 shows the main parts of the enterprise bean class for the example Account enterprise bean. (Emphasized code is in bold type.) The sections that follow discuss these parts in greater detail.
Figure 18. Code example: The AccountBean class
... import java.util.Properties; import javax.ejb.*; import java.lang.*; public class AccountBean implements EntityBean { // Set instance variables here ... // Implement methods here ... } |
Container-managed fields (which are persistent variables) are stored in a database. Container-managed fields must be public.
Nonpersistent variables are not stored in a database and are temporary. Nonpersistent variables must be used with caution and must not be used to maintain the state of an EJB client between method invocations. This restriction is necessary because nonpersistent variables cannot be relied on to remain the same between method invocations outside of a transaction because other EJB clients can change these variables, or they can be lost when the entity bean is passivated.
Also, container-managed fields in entity beans must be valid Java types, but they cannot be of type javax.ejb.Handle or an array of type EJBObject or EJBHome.
The AccountBean class contains three container-managed fields (shown in Figure 19):
Figure 19. Code example: The variables of the AccountBean class
... public class AccountBean implements EntityBean { private EntityContext entityContext = null; private ListResourceBundle bundle = ResourceBundle.getBundle( "com.ibm.ejs.doc.account.AccountResourceBundle"); public long accountId = 0; public int type = 1; public float balance = 0.0f; ... } |
The deployment descriptor is used to identify container-managed fields in entity beans with CMP. In an entity bean with CMP, each container-managed field must be initialized by each ejbCreate method (see Implementing the ejbCreate and ejbPostCreate methods).
A subset of the container-managed fields is used to define the primary key class associated with each instance of an enterprise bean. As is shown in Writing the primary key class (entity with CMP), the accountId variable defines the primary key for the Account enterprise bean. The AccountBean class contains two nonpersistent variables:
Therefore, for every business method implemented in the enterprise bean class, a corresponding method must be defined in the enterprise bean's remote interface. The enterprise bean's remote interface is implemented by the container in the EJB object class when the enterprise bean is deployed.
Figure 20 shows the business methods for the AccountBean class. These methods are used to add a specified amount to an account balance and return the new balance (add), to return the current balance of an account (getBalance), to set the balance of an account (setBalance), and to subtract a specified amount from an account balance and return the new balance (subtract). The subtract method throws the user-defined exception com.ibm.ejs.doc.account.InsufficientFundsException if a client attempts to subtract more money from an account than is contained in the account balance. The subtract method in the Account bean's remote interface must also throw this exception as shown in Figure 25. User-defined exception classes for enterprise beans are created as are any other user-defined exception class. The message content for the InsufficientFundsException exception is obtained from the AccountResourceBundle class file by invoking the getMessage method on the bundle object.
Figure 20. Code example: The business methods of the AccountBean class
... public class AccountBean implements EntityBean { ... public long accountId = 0; public int type = 1; public float balance = 0.0f; ... public float add(float amount) { balance += amount; return balance; } ... public float getBalance() { return balance; } ... public void setBalance(float amount) { balance = amount; } ... public float subtract(float amount) throws InsufficientFundsException { if(balance < amount) { throw new InsufficientFundsException( bundle.getMessage("insufficientFunds")); } balance -= amount; return balance; } ... } |
Version 1.1 of the EJB specification defines several standard application exceptions for use by enterprise beans. All of these exceptions are subclasses of the javax.ejb.EJBException class. For entity beans with both container- and bean-managed persistence, the EJB specification defines the following application exceptions:
Application programmers can use the generic EJBException class or one of the provided subclassed exceptions, or programmers can define their own exceptions by subclassing any of this family of exceptions. All of these exceptions inherit from the javax.ejb.RuntimeException class and do not have to be explicitly declared in throws clauses.
Each exception is discussed in more detail within the relevant section; for more information on:
Like the business methods of the bean class, the ejbCreate and ejbPostCreate methods cannot be invoked directly by the client. Instead, the client invokes the create method of the enterprise bean's home interface by using the EJB home object, and the container invokes the ejbCreate method followed by the ejbPostCreate method. If the ejbCreate and ejbPostCreate methods are executed successfully, an EJB object is created and the persistent data associated with that object is inserted into the data source.
For an entity bean with CMP, the container handles the required interaction between the entity bean instance and the data source between calls to the ejbCreate and ejbPostCreate methods. For an entity bean with BMP, the ejbCreate method must contain the code to directly handle this interaction. For more information on entity beans with BMP, see Developing entity beans with BMP.
Each ejbCreate method in an entity bean with CMP must meet the following requirements:
Each ejbPostCreate method must be public, return void, and have the same arguments as the matching ejbCreate method. If necessary, both the ejbCreate method and the ejbPostCreate method can throw the javax.ejb.EJBException exception or one of the creation-related subclasses, the CreateException or the DuplicateKeyException exceptions. The DuplicateKeyException class is a subclass of the CreateException class. Throwing the java.rmi.RemoteException exception is deprecated; see Standard application exceptions for entity beans for more information.
Figure 21 shows two sets of ejbCreate and ejbPostCreate methods required for the example AccountBean class. The first set of ejbCreate and ejbPostCreate methods are wrappers that call the second set of methods and set the type variable to 1 (corresponding to a savings account) and the balance variable to 0 (zero dollars).
Figure 21. Code example: The ejbCreate and ejbPostCreate methods of the AccountBean class
... public class AccountBean implements EntityBean { ... public long accountId = 0; public int type = 1; public float balance = 0.0f; ... public Integer ejbCreate(AccountKey key) { ejbCreate(key, 1, 0.0f); } ... public Integer ejbCreate(AccountKey key, int type, float initialBalance) throws EJBException { accountId = key.accountId; type = type; balance = initialBalance; } ... public void ejbPostCreate(AccountKey key) throws EJBException { ejbPostCreate(key, 1, 0); } ... public void ejbPostCreate(AccountKey key, int type, float initialBalance) { } ... } |
In entity beans with CMP, the container handles the required data source interaction for these methods. In entity beans with BMP, these methods must directly handle the required data source interaction. For more information on entity beans with BMP, see More-advanced programming concepts for enterprise beans.
These methods have several possible uses, including the following:
Figure 22. Code example: Implementing the EntityBean interface in the AccountBean class
... public class AccountBean implements EntityBean { private EntityContext entityContext = null; ... public void ejbActivate() throws EJBException { } ... public void ejbLoad () throws EJBException { } ... public void ejbPassivate() throws EJBException { } ... public void ejbRemove() throws EJBException { } ... public void ejbStore () throws EJBException { } ... public void setEntityContext(EntityContext ctx) throws EJBException { entityContext = ctx; } ... public void unsetEntityContext() throws EJBException { entityContext = null; } } |
The container makes the home interface accessible to enterprise bean clients through the Java Naming and Directory Interface (JNDI). JNDI is independent of any specific naming and directory service and allows Java-based applications to access any naming and directory service in a standard way.
By convention, the home interface is named NameHome, where Name is the name you assign to the enterprise bean. For example, the Account enterprise bean's home interface is named AccountHome. Every home interface must meet the following requirements:
Figure 23 shows the relevant parts of the definition of the home interface (AccountHome) for the example Account bean. This interface defines two abstract create methods: the first creates an Account object by using an associated AccountKey object, the second creates an Account object by using an associated AccountKey object and specifying an account type and an initial balance. The interface defines the required findByPrimaryKey method and a findLargeAccounts method, which returns a collection of accounts containing balances greater than a specified amount.
Figure 23. Code example: The AccountHome home interface
... import java.rmi.*; import java.util.*; import javax.ejb.*; public interface AccountHome extends EJBHome { ... Account create (AccountKey id) throws CreateException, RemoteException; ... Account create(AccountKey id, int type, float initialBalance) throws CreateException, RemoteException; ... Account findByPrimaryKey (AccountKey id) RemoteException, FinderException; ... Enumeration findLargeAccounts(float amount) throws RemoteException, FinderException; } |
Each create method must meet the following requirements:
At minimum, each home interface must define the findByPrimaryKey method that enables a client to locate an EJB object by using the primary key only. The findByPrimaryKey method has one argument, an object of the bean's primary key class, and returns the type of the bean's remote interface.
Every other finder method must meet the following requirements:
While every entity bean must contain the default finder method, you can write additional finder methods if needed. For example, the Account bean's home interface defines the findLargeAccounts method to find objects that encapsulate accounts with balances of more than a specified amount, as shown in Figure 24. Because this finder method can be expected to return a reference to more than one EJB object, its return type is Enumeration.
Figure 24. Code example: The findLargeAccounts method
Enumeration findLargeAccounts(float amount) throws RemoteException, FinderException; |
Every EJB server can implement the findByPrimaryKey method. During enterprise bean deployment, the container generates the code required to search the database for the appropriate enterprise bean instance.
However, for each additional finder method that you define in the home interface, the enterprise bean deployer must associate finder logic with that finder method. This logic is used by the EJB server during deployment to generate the code required to implement the finder method.
The EJB Specification does not define the format of the finder logic, so the format can vary according to the EJB server you are using. For more information on creating finder logic, see Creating finder logic in the EJB server (AE) or Creating finder logic in the EJB server (CB).
By convention, the remote interface is named Name, where Name is the name you assign to the enterprise bean. For example, the Account enterprise bean's remote interface is named Account. Every remote interface must meet the following requirements:
Figure 25 shows the relevant parts of the definition of the remote interface (Account) for the example Account enterprise bean. This interface defines four methods for displaying and manipulating the account balance that exactly match the business methods implemented in the AccountBean class. All of the business methods in the remote interface throw the java.rmi.RemoteException exception class. In addition, the subtract method must throw the user-defined exception com.ibm.ejs.doc.account.InsufficientFundsException because the corresponding method in the bean class throws this exception. Furthermore, any client that calls this method must either handle the exception or pass it on by throwing it.
Figure 25. Code example: The Account remote interface
... import java.rmi.*; import javax.ejb.*; public interface Account extends EJBObject { ... float add(float amount) throws RemoteException; ... float getBalance() throws RemoteException; ... void setBalance(float amount) throws RemoteException; ... float subtract(float amount) throws InsufficientFundsException, RemoteException; } |
Primary keys are specified in two ways:
The primary key class is used to manage an EJB object's primary key. By convention, the primary key class is named NameKey, where Name is the name of the enterprise bean. For example, the Account enterprise bean's primary key class is named AccountKey. The primary key class must meet the following requirements:
Figure 26 shows a composite primary key class for an example enterprise bean, Item. In effect, this class acts as a wrapper around the string variables productId and vendorId. The hashCode method for the ItemKey class invokes the corresponding hashCode method in the java.lang.String class after creating a temporary string object by using the value of the productId variable. In addition to the default constructor, the ItemKey class also defines a constructor that sets the value of the primary key variables to the specified strings.
Figure 26. Code example: The ItemKey primary key class
... import java.io.*; // Composite primary key class public class ItemKey implements java.io.Serializable { public String productId; public String vendorId; // Constructors public ItemKey() { }; public ItemKey(String productId, String vendorId) { this.productId = productId; this.vendorId = vendorId; } public String getProductId() { return productId; } public String getVendorId() { return vendorId; } ... // EJB server (AE)-specific method public boolean equals(Object other) { if (other instanceof ItemKey) { return (productId.equals(((ItemKey) other).productId) && vendorId.equals(((ItemKey) other).vendorId)); } else return false; } ... // EJB server (AE)-specific method public int hashCode() { return (new productId.hashCode()); } } |
A primary key class can also be used to encapsulate a primary key that is not known ahead of time -- for instance, if the entity bean is intended to work with several persistent data stores, each of which requires a different primary key structure. The entity bean's primary key type is derived from the primary key type used by the underlying database that stores the entity objects; it does not necessarily have to be known to the enterprise bean developer.
To specify an unknown primary key, do the following:
When the primary key selection is deferred to deployment, client applications cannot use methods that rely on knowledge of the primary key type. In addition, applications cannot always depend on methods that return the type of the primary key (such as the EntityContext.getPrimaryKey method) because the return type is determined at deployment.
This section contains general information and tips on enterprise beans and database access.
Shared database access corresponds to Option C caching. Option A and Option C caching are also known as commit option A and commit option C, respectively.
From a component perspective, one of the biggest differences between the two types of enterprise beans is that session beans do not have a primary key class and the session bean's home interface does not define finder methods. Session enterprise beans do not require primary keys and finder methods because session EJB objects are created, associated with a specific client, and then removed as needed, whereas entity EJB objects represent permanent data in a data source and can be uniquely identified with a primary key. Because the data for session beans is never permanently stored, the session bean class does not have methods for storing data to and loading data from a data source.
Every session bean must contain the following basic parts:
If a bean needs to synchronize its conversational state with the transactional context, the bean class must implement the javax.ejb.SessionSynchronization interface. This interface contains methods to notify the session bean when a transaction begins, when it is about to complete, and when it has completed. The enterprise bean developer can use these methods to synchronize the state of the session enterprise bean instance with ongoing transactions.
The enterprise bean class can implement the enterprise bean's remote interface, but this is not recommended. If the enterprise bean class implements the remote interface, it is possible to inadvertently pass the this variable as a method argument.
Figure 27 shows the main parts of the enterprise bean class for the example Transfer bean. The sections that follow discuss these parts in greater detail.
The Transfer bean is stateless. If the Transfer bean's transferFunds method were dependent on the value of the balance variable returned by the getBalance method, the TransferBean would be stateful.
Figure 27. Code example: The TransferBean class
... import java.rmi.RemoteException; import java.util.Properties; import java.util.ResurceBundle; import java.util.ListResourceBundle; import javax.ejb.*; import java.lang.*; import javax.naming.*; import com.ibm.ejs.doc.account.*; ... public class TransferBean implements SessionBean { ... private SessionContext mySessionCtx = null; private InitialContext initialContext = null; private AccountHome accountHome = null; private Account fromAccount = null; private Account toAccount = null; ... public void ejbActivate() throws EJBException { } ... public void ejbCreate() throws EJBException { ... } ... public void ejbPassivate() throws EJBException { } ... public void ejbRemove() throws EJBException { } ... public float getBalance(long acctId) throws FinderException, EJBException { ... } ... public void setSessionContext(javax.ejb.SessionContext ctx) throws EJBException { ... } ... public void transferFunds(long fromAcctId, long toAcctId, float amount) throws EJBException { ... } } |
Therefore, for every business method defined in the enterprise bean's remote interface, a corresponding method must be implemented in the enterprise bean class. The enterprise bean's remote interface is implemented by the container in the EJBObject class when the enterprise bean is deployed.
Figure 28 shows the business methods for the TransferBean class. The getBalance method is used to get the balance for an account. It first locates the appropriate Account EJB object and then calls that object's getBalance method.
The transferFunds method is used to transfer a specified amount between two accounts (encapsulated in two Account entity EJB objects). After locating the appropriate Account EJB objects by using the findByPrimaryKey method, the transferFunds method calls the add method on one account and the subtract method on the other. Like all finder methods, findByPrimaryKey can throw both the FinderException and RemoteException exceptions. The try/catch blocks are set up around invocations of the findByPrimaryKey method to handle the entry of invalid account IDs by users. If the session bean user enters an invalid account ID, the findByPrimaryKey method cannot locate an EJB object, and the finder method throws the FinderException exception. This exception is caught and converted into a new FinderException exception containing information on the invalid account ID.
To call the findByPrimaryKey method, both business methods need to be able to access the EJB home object that implements the AccountHome interface discussed in Writing the home interface (entity with CMP). Obtaining the EJB home object is discussed in Implementing the ejbCreate methods.
Figure 28. Code example: The business methods of the TransferBean class
public class TransferBean implements SessionBean { ... private Account fromAccount = null; private Account toAccount = null; ... public float getBalance(long acctId) throws FinderException, EJBException { AccountKey key = new AccountKey(acctId); try { fromAccount = accountHome.findByPrimaryKey(key); } catch(FinderException ex) { throw new FinderException("Account " + acctId + " does not exist."); } catch(RemoteException ex) { throw new FinderException("Account " + acctId + " could not be found."); } return fromAccount.getBalance(); } ... public void transferFunds(long fromAcctId, long toAcctId, float amount) throws EJBException, InsufficientFundsException, FinderException { AccountKey fromKey = new AccountKey(fromAcctId); AccountKey toKey = new AccountKey(toAcctId); try { fromAccount = accountHome.findByPrimaryKey(fromKey); } catch(FinderException ex) { throw new FinderException("Account " + fromAcctId + " does not exist."); } catch(RemoteException ex) { throw new FinderException("Account " + acctId + " could not be found."); } try { toAccount = accountHome.findByPrimaryKey(toKey); } catch(FinderException ex) { throw new FinderException("Account " + toAcctId + " does not exist."); } catch(RemoteException ex) { throw new FinderException("Account " + acctId + " could not be found."); } try { toAccount.add(amount); fromAccount.subtract(amount); } catch(InsufficientFundsException ex) { mySessionCtx.setRollbackOnly(); throw new InsufficientFundsException("Insufficient funds in " + fromAcctId); } } } |
Each ejbCreate method must correspond to a create method in the enterprise bean's home interface. (Note that there is no ejbPostCreate method in a session bean as there is in an entity bean.) Unlike the business methods of the enterprise bean class, the ejbCreate methods cannot be invoked directly by the client. Instead, the client invokes the create method in the bean instance's home interface, and the container invokes the ejbCreate method. If an ejbCreate method is executed successfully, an EJB object is created.
An ejbCreate method for a session bean must meet the following requirements:
The throws clause can define arbitrary application exceptions. The javax.ejb.EJBException or another runtime exception can be used to indicate non-application exceptions.
An ejbCreate method for an entity bean must meet the following requirements:
The throws clause can define arbitrary application exceptions. The javax.ejb.EJBException or another runtime exception can be used to indicate non-application exceptions. Figure 29 shows the ejbCreate method required by the example TransferBean class. The Transfer bean's ejbCreate method obtains a reference to the Account bean's home object. This reference is required by the Transfer bean's business methods. Getting a reference to an enterprise bean's home interface is a two-step process:
When a container invokes the Transfer bean's ejbCreate method, the enterprise bean's initialContext object is constructed by creating a Properties variable (env) that requires the following values:
The values of these properties are discussed in more detail in Creating and getting a reference to a bean's EJB object.
... public class TransferBean implements SessionBean { private static final String INITIAL_NAMING_FACTORY_SYSPROP = javax.naming.Context.INITIAL_CONTEXT_FACTORY; private static final String PROVIDER_URL_SYSPROP = javax.naming.Context.PROVIDER_URL; ... private String nameService = null; ... private String providerURL = null; ... private InitialContext initialContext = null; ... public void ejbCreate() throws EJBException { // Get the initial context try { Properties env = System.getProperties(); ... env.put( PROVIDER_URL_SYSPROP, getProviderUrl() ); env.put( INITIAL_CONTEXT_FACTORY_SYSPROP, getNamingFactory() ); initialContext = new InitialContext( env ); } catch(Exception ex) { ... } ... // Look up the home interface using the JNDI name ... } |
(Setting environment variables for an enterprise bean shows an example of the jetace page required to set these variables.)
Figure 30 illustrates the relevant parts of the getProviderURL method that is used to get the PROVIDER_URL property value. The javax.ejb.SessionContext variable (mySessionCtx) is used to get the Transfer bean's environment in the deployment descriptor by invoking the getEnvironment method. The object returned by the getEnvironment method can then be used to get the value of a specific environment variable by invoking the getProperty method.
Figure 30. Code example: The getProviderURL method
... public class TransferBean implements SessionBean { private SessionContext mySessionCtx = null; ... private String getProviderURL() throws RemoteException { //get the provider URL property either from //the EJB properties or, if it isn't there //use "iiop:///", which causes a default to the local host ... String pr = mySessionCtx.getEnvironment().getProperty( PROVIDER_URL_SYSPROP); if (pr == null) pr = "iiop:///"; return pr; } ... } |
An enterprise bean is accessed by looking up the class implementing its home interface by name through JNDI. Methods on the home interface provide access to an instance of the class implementing the remote interface.
After constructing the InitialContext object, the ejbCreate method performs a JNDI lookup using the JNDI name of the Account enterprise bean. Like the PROVIDER_URL and INITIAL_CONTEXT_FACTORY properties, this name is also retrieved from an environment variable contained in the Transfer bean's deployment descriptor (by invoking a private method named getHomeName). The lookup method returns an object of type java.lang.Object.
The returned object is narrowed by using the static method javax.rmi.PortableRemoteObject.narrow to obtain a reference to the EJB home object for the specified enterprise bean. The parameters of the narrow method are the object to be narrowed and the class of the object to be created as a result of the narrowing. For a more thorough discussion of the code required to locate an enterprise bean in JNDI and then narrow it to get an EJB home object, see Creating and getting a reference to a bean's EJB object.
... public class TransferBean implements SessionBean { ... private String accountName = null; ... private InitialContext initialContext = null; ... public void ejbCreate() throws EJBException { // Get the initial context ... // Look up the home interface using the JNDI name try { java.lang.Object ejbHome = initialContext.lookup(accountName); accountHome = (AccountHome)javax.rmi.PortableRemoteObject.narrow( (org.omg.CORBA.Object) ejbHome, AccountHome.class); } catch (NamingException e) { // Error getting the home interface ... } ... } ... } |
The enterprise bean's environment is implemented by the container. It enables the bean's business logic to be customized without the need to access or change the bean's source code. The container provides an implementation of the JNDI naming context that stores the enterprise bean environment. Business methods access the environment by using the JNDI interfaces. The deployment descriptor provides the environment entries that the enterprise bean expects at runtime.
Each enterprise bean defines its own environment entries, which are shared between all of its instances (that is, all instances with the same home). Environment entries are not shared between enterprise beans.
An enterprise bean's environment entries are stored directly in the environment naming context (or one of its subcontexts). To retrieve its environment naming context, an enterprise bean instance creates an InitialContext object by using the constructor with no arguments. It then looks up the environment naming via the InitialContext object under the name java:comp/env.
The enterprise bean in Figure 32 changes an account number by looking up an environment entry to find the new account number.
Figure 32. Code example: Looking up an enterprise bean's environment naming context
public class AccountService implements SessionBean { ... public void changeAccountNumber(int accountNumber, ... ) throws InvalidAccountNumberException{ .... // Obtain the bean's environment naming context Context initialContext = new InitialContext(); Context myEnvironment = (Context)initialContext.lookup("java:comp/env); ... // Obtain new account number from environment Integer newNumber = (Integer)myEnvironment.lookup("newAccountNumber"); ... } } |
A session context can be used to get a handle to a particular instance of a stateful session bean. It can also be used to get a reference to a transaction context object, as described in Using bean-managed transactions.
Figure 33. Code example: Implementing the SessionBean interface in the TransferBean class
... public class TransferBean implements SessionBean { private SessionContext mySessionCtx = null; ... public void ejbActivate() throws EJBException { } ... public void ejbPassivate() throws EJBException { } ... public void ejbRemove() throws EJBException { } ... public void setSessionContext(SessionContext ctx) throwEJBException { mySessionCtx = ctx; } ... } |
By convention, the home interface is named NameHome, where Name is the name you assign to the enterprise bean. For example, the Transfer enterprise bean's home interface is named TransferHome. Every session bean's home interface must meet the following requirements:
Figure 34 shows the relevant parts of the definition of the home interface (TransferHome) for the example Transfer bean.
Figure 34. Code example: The TransferHome home interface
... import javax.ejb.*; import java.rmi.*; public interface TransferHome extends EJBHome { Transfer create() throws CreateException, RemoteException; } |
Each create method must be named create and have the same number and types of arguments as a corresponding ejbCreate method in the EJB object class. The return types of the create method and its corresponding ejbCreate method are always different. Each create method must meet the following requirements:
By convention, the remote interface is named Name, where Name is the name you assign to the enterprise bean. For example, the Transfer enterprise bean's remote interface is named Transfer. Every remote interface must meet the following requirements:
Figure 35 shows the relevant parts of the definition of the remote interface (Transfer) for the example Transfer bean. This interface defines the methods for transferring funds between two Account bean instances and for getting the balance of an Account bean instance.
Figure 35. Code example: The Transfer remote interface
... import javax.ejb.*; import java.rmi.*; import com.ibm.ejs.doc.account.*; public interface Transfer extends EJBObject { ... float getBalance(long acctId) throws FinderException, RemoteException; ... void transferFunds(long fromAcctId, long toAcctId, float amount) throws InsufficientFundsException, RemoteException; } |
Enterprise beans must implement the interfaces described here in the appropriate enterprise bean component.
These methods have the following syntax:
public abstract EJBHome getEJBHome(); public abstract Handle getHandle(); public abstract Object getPrimaryKey(); public abstract boolean isIdentical(EJBObject obj); public abstract void remove(); |
These methods are implemented by the container in the EJB object class.
The remove methods are used to remove an existing EJB object (and its associated data in the database) either by specifying the EJB object's handle or its primary key. (The remove method that takes a primaryKey variable can be used only in entity beans.) The getEJBMetaData method is used to obtain metadata about the enterprise bean and is mainly intended for use by development tools.
These methods have the following syntax:
public abstract EJBMetaData getEJBMetaData(); public abstract void remove(Handle handle); public abstract void remove(Object primaryKey); |
The javax.ejb.EJBHome interface also contains a method to get a handle to the home interface. It has the following syntax:
public abstract HomeHandle getHomeHandle();
If you attempt to use a parameter that is not valid, the java.rmi.RemoteException exception is thrown. Note that the following atypical types are not valid:
The EJB server (AE) enforces single-threaded access to all enterprise beans. Illegal callbacks result in a java.rmi.RemoteException exception being thrown to the EJB client.
The EJB server (CB) enforces single-threaded access to enterprise beans only if their transaction attribute is set to either TX_NOT_SUPPORTED or TX_BEAN_MANAGED. For other enterprise beans, access from different transactions is serialized, but serialized access from different threads running under the same transaction is not enforced. For enterprise beans deployed with the transaction attribute value of TX_NOT_SUPPORTED or TX_BEAN_MANAGED, illegal callbacks result in a RemoteException exception being thrown to the EJB client.
If you develop enterprise beans in an IDE, these tasks are handled from within the tool that you use. If you do not develop enterprise beans in an IDE, you must handle each of these tasks by using tools contained in the Java Software Development Kit (SDK) and WebSphere Application Server.
package com.ibm.ejs.doc.account;
All of the Java source files that make up the Transfer bean contain the following package statement:
package com.ibm.ejs.doc.transfer;
An EJB module contains one or more deployable enterprise beans. It also contains a deployment descriptor that provides information about each enterprise bean and instructions for the container on how to handle all enterprise beans in the module. The deployment descriptor is stored in an XML file.
During creation of the EJB module, you specify the files for each enterprise bean to be included in the module. These files include:
You also specify other information about the bean, such as references to other enterprise beans, resource factories, and security roles. After defining the enterprise beans to be included in the module, you specify application assembly instructions that apply to the module as a whole. Both bean and module information are used to create a deployment descriptor. See The deployment descriptor for a list of deployment descriptor settings and attributes.