11.3. Migration to EJB: First Steps

As a first step in the migration to the EJB component model, one of the simpler CBOs was re-implemented as an EJB component.

The Currency CBO was chosen because it is a self-contained bean with a simple interface, without dependencies on other parts of EDH, and is based on a single table.

The Currency CBO is defined according to Figure 11.5

Figure 11.5. The Currency Business Object Interface


All the CBOs are defined as interfaces with an underlying implementation class. It was designed this way so that the implementation could be replaced at a later date, without having to change any client code.

The Currency CBO uses only a single database table. Each instance of a Currency CBO maps to a single row in the EDHCUR currency table (see Figure 11.6).

Figure 11.6. The Currency Table


The CurrencyHome provides the definition of the finder methods (see Figure 11.7). Because the Currency CBO is read-only, there is neither a create() method in the Home interface, nor setXXX() methods in the actual bean. Within a servlet, the program obtains a reference to a class that implements the CurrencyHome interface by calling the findByName("X") method of the HomeHome interface.

Figure 11.7. The CurrencyHome interface


The HomeHome interface performs the same role as the lookup() method in a JNDI context. The implementation does not make use of JNDI, but instead employs Class.forName() to obtain a reference to an implementation of the Home interface.

The CurrencyService supplies the interface to the relational database (see Figure 11.8). As a measure to improve the maintainability of EDH, all the SQL for a particular CBO was located in a single class, rather than spread over the code. By grouping together all the SQL into one place, it is easier to identify which statements need to be changed if the underlying tables change their definition (as they have done in the past for tables provided by third-party products). JDBC is preferable for dynamic SQL, and SQLJ for static SQL. Developers often use SQLJ because it gives the ability to embed static SQL in Java code, thereby raising the level of abstraction, resulting in increased productivity. The Oracle JDBC drivers support the JDBC 2.0 standard. They also provide support for Oracle-defined extensions for Oracle datatypes, connection pooling, and distributed transactions.

Figure 11.8. The CurrencyService Class


11.3.1. The Currency Bean

In updating the application to an EJB implementation, the Currency and CurrencyHome interfaces were kept, but were implemented using EJBs. The remainder of the EDH application could then conveniently be used to test the new EJB implementation. Eventually, the interface could be extended to also allow updates of the exchange rate (restricted to the accounting department).

A wizard in Oracle JDeveloper allows for the creation of a Container-Managed Persistence (CMP) Entity Bean by pointing to the existing currency table, EDHCUR, and indicating the primary key and which columns need persisting. By default, the field names of the EJB correspond to the column names in the table, but you can override this. With this information, the wizard creates the remote interface (Currency.java), the home interface (CurrencyHome.java), its implementation (which was called CurrencyCMPBean.java), and the standard deployment descriptor (Currency.xml), as well as the vendor-specific descriptor (Currency_oracle.xml).

Oracle EJE provides a hook to plug in custom Object Relational (O/R) mapping through the Persistence Storage Interface (PSI). This is a Java API that allows container-managed persistence (CMP) providers, such as Oracle Business Components for Java, to manage O/R mappings from entity beans to database entities. You can use JDeveloper's wizards to design an O/R mapping that Oracle Business Components for Java manages with the PSI. An entity Bean class also needs a primary key, corresponding to one or more columns of the table, that allows instances to be retrieved using the findByPrimaryKey() method. CMP beans can also make use of other business component classes: domains that allow EJB fields to be based on Oracle object types, and secondary-view objects corresponding to EJB finder methods. Using the EJB/Oracle9i Deployment Object Wizard in Oracle JDeveloper, CMP persistence can be added to the entity bean.

Figure 11.9. Oracle JDeveloper EJB Designer Screen


The following code excerpt shows the method declarations for the Currency.java interface.

public interface Currency  extends javax.ejb.EJBObject
{
     public String getName(Locale lang) throws java.rmi.RemoteException;
     public double getExchangeRate()    throws java.rmi.RemoteException;
     public void setExchangeRate(double newExchangeRate)
                                        throws java.rmi.RemoteException;
...

In the following excerpt from Currency-oracle.xml, the Oracle-specific deployment descriptor mainly defines the mapping of the Currency bean (in the package cern.base) to its JNDI name ais/base/Currency. In addition, it specifies the CMP provider (here the simple reference implementation PSI-RI was used) and the mapping of the columns in the database table to their field names.

<oracle-descriptor>
   <mappings>
     <ejb-mapping>
     <ejb-name>Currency</ejb-name>
   <jndi-name>ais/base/Currency</jndi-name>
</ejb-mapping>
</mappings>
<persistence-provider>
   <description> demo persistence manager </description>
   <persistence-name>psi-ri</persistence-name>
   <persistence-deployer>
      oracle.aurora.ejb.persistence.ocmp.OcmpEntityDeployer
   </persistence-deployer>
</persistence-provider>
<persistence-descriptor>
   <description> simple persistence-mapping  </description>
   <ejb-name>Currency</ejb-name>
   <persistence-name>psi-ri</persistence-name>
   <psi-ri>
      <schema>demo</schema>
      <table>edhcur</table>
      <attr-mapping>
         <field-name>CurrencySymbol</field-name>
         <column-name>CUR</column-name>
      </attr-mapping>
      <attr-mapping>
         <field-name>EnglishDesc</field-name>
         <column-name>ELG</column-name>
      </attr-mapping>
      <attr-mapping>
         <field-name>ExchangeRate</field-name>
         <column-name>EXG</column-name>
      </attr-mapping>
...

The EJB designer in JDeveloper can be used to further define the remote and home interfaces. After this, business logic is added to the bean implementation. For example, in the setExchangeRate() you could check whether the new value is within the same range of the existing value, to reduce data-entry errors. The getName() method was also added to support more languages in the future, without changing the interface. After this, the bean is ready to be deployed to the Oracle container.

Because Container-Managed Persistence was chosen, the container automatically invokes a persistence manager on behalf of the bean, without any extra programming to load or store the data in the database. In addition, you automatically get many CMP-only finder methods to perform a SQL query against the persistent data table (findAllCurrencys takes a string that denotes the “where” clause of a SQL query). Assuming the CurrencyHome, curHome, was obtained, all Currencies can be listed (Collections are not currently supported).

Currency cur;
Enumeration e = curHome.findAllCurrencys("");
while(e.hasMoreElements())
{
     cur = (Currency) e.nextElement();
     System.out.println (" name = " +  cur.getName(Locale.ENGLISH)+
                         " has rate = " + cur.getExchangeRate() );
}

11.3.2. The Converter Bean

With the Currency Bean defined, a facility was added to convert any amount from one currency to another through a converter Stateless Session Bean in the same cern.base package. After creating the bean through the appropriate wizard in JDeveloper, the interface files, the bean implementation, and the deployment descriptors are automatically generated. The remote interface in Converter.java is

public interface Converter extends javax.ejb.EJBObject
{
      double convert (Currency from, Currency to, double amount)
                        throws  java.rmi.RemoteException;
}

Its implementation in the bean is as follows:

public double convert (Currency from, Currency to, double amount)
             throws java.rmi.RemoteException
{
     return ( to.getExchangeRate() / from.getExchangeRate() ) *
    amount;
}

After deploying to the container, you can now write the following client code.

// Create the currencies we want to convert from their primary key
// (ISO Code)
Currency swissFrancs = curHome.findByPrimaryKey("CHF");
Currency euro = curHome.findByPrimaryKey("EUR");

// Obtain a new Exchange Calculator from the
// ConverterHome interface convHome
Converter myXChangeCalc = convHome.create();

System.out.println("150 " + swissFrancs.getEnglishDesc() +
                   " corresponds to " +
                   myXChangeCalc.convert(swissFrancs, euro, 150f)
                   + " " + euro.getEnglishDesc());

// Clean up neatly
myXChangeCalc.remove();

Which produces the following:

150 Swiss Franc corresponds to 97.4 Euro.

11.3.3. Taking Stock

The Currency Entity Bean can be accessed by anyone through its JNDI name. During deployment of the EJB, access rights are set up so that exchange rates can be updated only centrally from the accounting department, with the setExchangeRate() method. Because the beans and the database table reside in the same database, the loading and storing of data is efficient. Any changes to the underlying database table will affect only our bean.

Any application that wants to use the Converter retrieves these new rates immediately. The remote convert method call will access the exchange rates of the two Currency beans that reside in the same container, and there is no further overhead.

After the first simple EJB was completed, we were ready to tackle a more complex example.

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

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