Aggregation of Enterprise Beans


The topic that we wish to discuss in this section relates to the (sometimes run-time) aggregation of Enterprise Beans and the creation of a cooperative environment for Enterprise Bean components on the server side. We would like to mention briefly the various standard alternatives, so that we can present later in the section an application-oriented aggregation plan.

Alternative 1: Static Aggregation over the Client View

A (static) aggregation of components is possible, in that they operate over the view of a client (see the subsection on the client view in Chapter 4). Information is placed in the section ejb-ref of the deployment descriptor that describes the type of Enterprise Beans that will be used by beans to be installed over the client view. Through the field ejb-link the application assembler binds these references to concrete installed implementations of this bean type. Through the use of the local client view, communication among Enterprise Beans can be optimized when they are installed in the same application server.

Alternative 2: Dynamic Aggregation over the Metadata Interface

For the run-time dynamic aggregation, the specification of Enterprise JavaBeans offers the metadata interface (javax.ejb.EJBHome.getEJBMetaData). In combination with the Java reflection API it is possible to program dynamic method calls in Enterprise Beans. Such an aggregation is very generic and relatively expensive in programming effort. Data type checking during compilation is lost. Moreover, the use of the Java reflection API is always critical for execution speed. One often wishes to have a less generic but better-performing option for dynamic aggregation of Enterprise Beans at run time. Furthermore, this type of dynamic aggregation is limited to the remote client view. The method getEJBMetaData in javax.ejb.EJBLocalHome is not available.

Alternative 3: Dynamic Aggregation over Events

A common type of dynamic aggregation of components consists of events (see the section after next). An event model, similar to that for JavaBeans, by which Enterprise Beans trigger events via the EJB container and can receive events, would be ideal for the dynamic aggregation of Enterprise Bean components at run time. If the triggering and receiving of events is possible only via the EJB container, then there is no conflict with life cycle management or client calls. For example, the EJB container can block client calls or the passivation or deletion of an Enterprise Bean until the processing of a received event is complete, or suppress the assignment of events to passivated or deleted Enterprise Beans. The specification for Enterprise JavaBeans provides no event model for Enterprise Beans, and therefore an aggregation over events is not possible.

Alternative 4: Dynamic Aggregation over Messages

Another common type of dynamic aggregation is the exchange of messages over a message service such as the Java Message Service. However, the Java Message Service is designed for communication between processes over a network. For communication strictly within a process it is not very efficient. Furthermore, an entity bean or a session bean cannot use asynchronous message delivery over the javax.jms.MessageListener interface (see Chapter 6), since the specification explicitly forbids it. If it were to permit this mechanism for entity and session beans, the result could be conflicts between the life cycle management of the EJB container and message delivery through the JMS provider. Furthermore, the justification for the existence of message-driven beans would be called into question. Therefore, the Java Message Service is unsuitable for dynamic aggregation of Enterprise Beans.

Alternative 5: Static Aggregation over the Creation of an Enterprise Bean

The application assembler can enable an aggregation of Enterprise Beans using the specification by programming a new Enterprise Bean. The client would use the Enterprise Bean of the application assembler, which uses other beans for carrying out desired tasks and enables their cooperation.

Alternative 6: Aggregation of Entity Beans over Persistent Relationships

Persistent relationships (container-managed relationships) are in a certain sense also a means of collecting Enterprise Bean components into aggregates. This is, on the one hand, a static aggregation, since the relationships are set in the deployment descriptor and are thus limited to particular types of Enterprise Beans. However, the actual aggregation between the instances of the Enterprise Beans involved in the relationship is dynamic, since the connection between the instances (which are implemented, for example, in a database via a foreign key relation) can be created or deleted at run time. The example of warehouse management in Chapter 5 illustrates this situation. Communication among the Enterprise Beans aggregated in this manner takes place over the local client view and is therefore relatively efficient. The resolution of references among entity bean instances arising from the relationship is taken over by the EJB container. Persistent relationships are thus the only form of aggregation that is actively supported by the EJB container. This type of aggregation is, however, relevant to entity beans only.

In addition to alternative 6, alternatives 1, 2, and 5 are relevant for the aggregation of Enterprise Beans. In the remainder of this section we would like to show a further alternative for the aggregation of Enterprise Beans and the creation of a cooperative environment.

Through a server-side application-oriented framework a cooperative environment can be created that enables Enterprise Beans to link dynamically and replace each other as necessary without other beans being affected. To illustrate, we shall develop an application-oriented framework for a simple accounting application. This framework (which serves the subject-matter aspects) rests on a system-oriented framework (which covers the technical requirements) and offers loose and dynamic coupling of Enterprise Beans (without a new bean having to be programmed). For this we use the previously introduced example from this chapter of the bookkeeping system.

We first present a traditional form of implementation in order to point out the differences in using a framework (which will be discussed afterwards).

Figure 9-6 shows the session bean Booking, which provides the client with an interface for carrying out double-entry bookkeeping. It uses the entity bean Account and the session bean JournalService for booking the entry.

click to expand
Figure 9-6: Example— Accounting application.

The code of a traditional client program might look something like that of Listing 9-2.

Listing 9-2: Example of a traditional client.

start example
 ... InitialContext ctx = new InitialContext(); //fetch the home interface of the session bean Booking final String BOOKING = "java:comp/env/ejb/Booking"; Object o = ctx.lookup(BOOKING); BookingHome bh = (BookingHome)        PortableRemoteObject.narrow(o, BookingHome.class); //generate the BookingBean and fetch the remote interface Booking b = bh.create(); //execute the booking b.setDebitAccount("0815"); b.setCreditAccount("0915"); b.setAmount(100); b.book(); b.remove(); ... 
end example

The implementation of the relevant methods of the remote interface in the BookingBean class would look something like that of Listing 9-3, using the traditional way of proceeding.

Listing 9-3: Example of a traditional session bean implementation.

start example
 ... private Account debitAccount; private Account creditAccount; private AccountHome accountHome; private JournalServiceHome journalHome; ... public void ejbCreate()   throws RemoteException, CreateException {  final String ACCHOME = "java:comp/env/ejb/Account";  final String JHOME = "java:comp/env/ejb/JournalService";  ...  try {   //fetch the home interface of the entity bean Account and   //the session bean JournalService   Context ctx = new InitialContext();   Object o = ctx.lookup(ACCHOME);   accountHome = (AccountHome)       PortableRemoteObject.narrow(o, AccountHome.class);   o = ctx.lookup(JHOME);   journalHome = (JournalServiceHome)       PortableRemoteObject.narrow                   (o,JournalServiceHome.class);  }  ... } ... public void setDebitAccount(String accno)   throws RemoteException, BookingException {  ... //check routines  //generate a PrimaryKey object  AccountPK pk = new AccountPK(accno);  try {   //search the debit account   debitAccount = accountHome.findByPrimaryKey(pk);  }  ... //error handling } public void setCreditAccount(String accno)   throws RemoteException, BookingException {  ... //check routines  //generate a PrimaryKey object  AccountPK pk = new AccountPK(accno);  try {   //search the credit account   creditAccount = accountHome.findByPrimaryKey(pk);  }  ... //error handling } ... public void setAmount(float amount)   throws RemoteException, BookingException {  ... //check routines  try {   //check whether the booking of the amount is permissible   debitAccount.checkAmount(amount * (-1));   creditAccount.checkAmount(amount);  }  ... //error handling } ... public void book()   throws RemoteException, BookingException {  ... //check routines  //booking of the amount by changing the account states  debitAccount.setBalance(debitAccount.getBalance()-                                theAmount);  creditAccount.setBalance(creditAccount.getBalance()+                                theAmount);  ... //error handling  //logging of the process in the journal  JournalService js = journalHome.create();  js.record(debitAccount,            creditAccount,            theAmount,            theContext.getCallerPrincipal());  ... //error handling } ... 
end example

The dependence of the session bean Booking on the entity bean Account and the session bean JournalService is documented in the deployment descriptor in Listing 9-4.

Listing 9-4: Example of a traditional deployment descriptor.

start example
 ... <ejb-jar>   <description>     This jar file contains all components     needed for the bookkeeping application   </description>     <enterprise-beans>       <session>         <description>           The session bean Booking provides           an implementation for the execution           of a double-entry bookkeeping system.         </description>         <ejb-name>Booking</ejb-name>         ...         <ejb-ref>           <ejb-ref-name>ejb/JournalService</ejb-ref-name>           <ejb-ref-type>Session</ejb-ref-type>           <home>ejb.example.JournalServiceHome</home>           <remote>ejb.example.JournalService</remote>           <ejb-link>JournalService</ejb-link>         </ejb-ref>         <ejb-ref>           <ejb-ref-name>ejb/Account</ejb-ref-name>           <ejb-ref-type>Entity</ejb-ref-type>           <home>ejb.example.AccountHome</home>           <remote>ejb.example.Account</remote>           <ejb-link>Account</ejb-link>         </ejb-ref>         ...       </session>       ...     </enterprise-beans> ... </ejb-jar> 
end example

As can be seen from these code fragments, the session bean Booking works directly with other beans. In the deployment descriptor the type of beans used is defined, and it must agree with the type used in the implementation. Should the need arise to replace, say, the Account bean with another type due to limited functionality or to use various types of accounts (which are also available as components), this would be possible only by changing the code of the session bean Booking. It would be possible using the ejb-link element of the deployment descriptor to bind the bean reference to another implementation of the same type. However, then a reinstallation of the session bean Booking would be necessary.

To eliminate the strict binding of the beans to each other they are embedded in an application-specific framework, allowing them to work together on a more abstract level (see Figure 9-7).

click to expand
Figure 9-7: Booking with a framework.

The session bean Booking is the business process that the client wishes to work with, and this session bean still represents the server interface. The use of the JournalService and Account beans should take place over the abstract interfaces of a framework , which allows the inclusion of accounts and a journal service in the accounting process.

The framework represented in Figure 9-8 consists in our example simply of the three depicted interfaces. The framework becomes concretized and applicable through the implementation of these interfaces in Java classes. The functionality that we expect from an account and a journal service is contained in the Enterprise Beans. To bridge the gap between the framework implementation and the Enterprise Beans, we make use of the bridge pattern (see [5]). This allows the various abstractions (account, journal) to be decoupled from their implementations and thus remain flexible.

click to expand
Figure 9-8: Application-oriented cooperation framework.

Figure 9-9 shows the classes JounalIF_Impl and AccountIF_Impl. They are generated on the initiative of the session bean Booking through the implementation of the interface AccountingFactory and used for the required operations. The implementation classes delegate the relevant method calls to other Enterprise Beans (in our case to the JournalService and Account beans). Thus the beans JournalService and Account are fully decoupled from the component Booking. Finally, it depends on the bridge classes as to which Enterprise Beans are actually used. Above all, this decision can be made at run time (with the proper implementation) based on conditions at the time.


Figure 9-9: Example of cooperation in a framework.

The references to the Account and JournalService beans no longer need to be specified as bean references in the deployment descriptor of the session bean Booking. Access to both beans by the session bean Booking no longer takes place over JNDI, but over the framework. Nonetheless, it is worth noting that in the deployment descriptor the session bean uses the implementation class of the framework. The deployment descriptor should in any case be used in its capacity as central repository of installation instructions. The resulting documentation effect is very useful. Unfortunately, there is no place in the sections of the deployment descriptor in which one may register the factory class (which is the entry point into the framework). In view of the configuration options, an entry as resource factory reference is the most suitable [21]. Nonetheless, the implementation class of the AccountingFactory interface and our framework in no way corresponds to what the specification understands by a resource factory and a resource. We shall therefore limit ourselves to a note in the description field of the session bean Booking (see Listing 9-5).

Listing 9-5: Example: deployment descriptor with framework.

start example
 ... <ejb-jar>   <description>     This jar file contains all components     necessary for the bookkeeping application.   </description>     <enterprise-beans>       <session>         <description>           The session bean Booking provides           an implementation for the execution           of double-entry accounting.           NOTE: This bean uses the           Accounting framework !         </description>         <ejb-name>Booking </ejb-name>         ...       </session>       ...     </enterprise-beans> </ejb-jar> 
end example

The implementation class of the AccountingFactory interface (FactoryImpl) is implemented as a singleton (see [5]; it will be treated following the modified implementation of the Booking class). This will avoid the generation of an instance via the bean class, and the management of the framework classes can be carried out at a central location in the process. The implementation in the bean class Booking would change as in Listing 9-6.

Listing 9-6: Example: session bean with framework.

start example
 ...   private AccountFactory theFactory;   private AccountIF debitAccount;   private AccountIF creditAccount;   ...   public void ejbCreate()     throws RemoteException, CreateException   {     ...     //fetch the factory implementation     theFactory = FactoryImpl.getFactory();     ...   } ...   public void setDebitAccount(String accno)     throws RemoteException, Booking Exception   {     ... //check routines     try {      //search the debit account         debitAccount = theFactory.createAccount(accno);     }         .. //error handling   }   public void setCreditAccount(String accno)       throws RemoteException, Booking Exception   {    ... //check routines    try {     //search the credit account     creditAccount = theFactory.createAccount(accno);    }    ... //error handling   }   ...   public void setAmount(float amount)     throws RemoteException, Booking Exception   {     //no changes    ...   }   ...   public void book()     throws RemoteException, Booking Exception   {    ...    //no changes    ...  //log the process in the journal  JournalIF js = theFactory.createJournalService();  js.record(debitAccount,            creditAccount,            theAmount,            theContext.getCallerPrincipal());  ... } ... 
end example

The implementation of the AccountingFactory interface is shown in Listing 9-7.

Listing 9-7: Example: factory interface implementation.

start example
 ... public class FactoryImpl implements AccountingFactory,                                     java.io.Serializable {     private static AccountingFactory theFactory =                                          new FactoryImpl();     private FactoryImpl() {}     public static AccountingFactory getFactory() {         return theFactory;     }     public AccountIF createAccount(String accountNumber)         throws AccountException     {         return new AccountIF_Impl(accountNumber);     }     public JournalIF createJournalService()         throws JournalException     {         return new JournalIF_Impl();     } } 
end example

The implementation of the interface java.io.Serializable is necessary to avoid problems with the passivation of stateful session beans that store a reference to an object of this class in a member variable.

The classes AccountIF_Impl and JournalIF_Impl implement the relevant interfaces (including the interface java.io.Serializable) and delegate the calls to the respective beans. To clarify this we show in Listing 9-8 the constructor and a method of the class AccountIF_Impl.

Listing 9-8: Example: interface implementation.

start example
 ... public class AccountIF_Impl implements AccountIF,                                        java.io.Serializable {     //the remote interface of the Account bean     Account theAccount;     public AccountIF_Impl(String accountNumber)         throws AccountException     {         final String ACCHOME = "java:comp/env/ejb/Account";         AccountPK pk = new AccountPK(accountNumber);         //here a run-time decision can be made as to         //which bean should be used         try {             AccountHome home;             InitialContext ctx = new InitialContext();             Object o = ctx.lookup(ACCHOME);             home = (AccountHome)                       PortableRemoteObject.narrow                           (o, AccountHome.class);             theAccount = home.findByPrimaryKey(pk);         }         catch(NamingException nex) {             throw new AccountException(nex.getMessage());         }         catch(FinderException fex) {             throw new AccountException(fex.getMessage());         }         catch(RemoteException rex) {             throw new AccountException(rex.getMessage());         }     }   ...     public String getAccountNumber()         throws AccountException     {         String ret;         try {             ret = theAccount.getAccountNumber();         }         catch(RemoteException rex) {             throw new AccountException(rex.getMessage());         }         return ret;     }     public String getAccountDescription()         throws AccountException     {         String ret;         try {             ret = theAccount.getAccountDescription();         }         catch(RemoteException rex) {             throw new AccountException(rex.getMessage());         }         return ret;     }   ... } 
end example

Summary

An application-oriented framework on the server side offers the possibility of coupling Enterprise Beans loosely and run-time dynamically. One can create an application-oriented cooperation framework. Moreover, the application assembler can provide additional code necessary for the correct coupling of the Enterprise Beans (glue code). This option also exists when custom Enterprise Beans are developed for the purpose of the coupling. Thanks to the application-oriented framework (even after deployment), the Enterprise Beans remain exchangeable without a repetition of the deployment process or the Enterprise Bean's code having to be altered. At run time a decision can be made as to which components are to be used. This is useful, for example, when there is not a single Account bean, but several, and a decision must be made, depending on the account numbers, as to which bean type will be used (for example, securities account or cash account). The handling of various account types is then also hidden from the session bean.

In our case, the framework must be supplied by the provider of the session bean Booking (since the provider programs directly to its interfaces). The application assembler would analogously implement the interfaces of the framework and likewise install the beans used by the implementation classes in the server. It is advisable to note in the beans' description fields that they will be used by the framework classes in order to maintain the central documentation function of the deployment descriptor. The application assembler also decides through the implementation which Enterprise Beans will be used as accounts or journal service, and can provide the additional code necessary for the application.




Enterprise JavaBeans 2.1
Enterprise JavaBeans 2.1
ISBN: 1590590880
EAN: 2147483647
Year: 2006
Pages: 103

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net