EJB Inheritance in WSAD





EJB Inheritance in WSAD

So far, you have seen a lengthy discussion about one of the two types of relationships (associations) defined in UML, and how associations between EJBs can be implemented in WSAD.

The second type of relationship is generalization. There are two types of generalizations that we can discuss—the inheritance relationship, which corresponds to the notion of implementation inheritance (extends in Java) and the realization relationship, which corresponds to the notion of interface inheritance (implements in Java). We will need to keep these two notions clear as we navigate the sea of what generalization means to EJBs.

The EJB specification is a little vague on the subject of inheritance. There are only two clear indications in the EJB specification about what inheritance means in the context of EJBs.

First, the EJB 2.0 specification states, "The remote interface is allowed to have super interfaces. Use of interface inheritance is subject to the RMI-IIOP rules for the definition of remote interfaces."[2] It also states "The remote home interface is allowed to have super interfaces. Use of interface inheritance is subject to the RMI-IIOP rules for the definition of remote interfaces."[3] The specification indicates requirements of only the remote interfaces, it does not state any inheritance requirements for the local interface or the local home interface.

[2] [EJB 99], p. 194.

[3] ibid, p. 194.

There are only two other places in the 2.0 specification that refer to inheritance. In both the session bean and entity bean scenarios, all three of home and remote interfaces and bean implementations are shown in a generalization relationship to other respective interfaces and implementations. However the spec is vague on how this can be accomplished.

For instance, in the entity bean scenario in Chapter 15, it states "…tools can use inheritance, delegation, and code generation to achieve mix-in of the two classes [participating in the generalization relationship]."

The EJB 2.0 specification clarifies this situation in its FAQ. It specifically states that component inheritance (i.e., how an entire EJB descends from another EJB) is beyond the scope of the specification due to the complexities involved in component inheritance. However, it discusses how developers can take advantage of the Java language support for inheritance as follows:

  • Interface inheritance. It is possible to use the Java language interface inheritance mechanism for inheritance of the home and remote interfaces. A component may derive its home and remote interfaces from some "parent" home and remote interfaces; the component then can be used anywhere where a component with the parent interfaces is expected. This is a Java language feature, and its use is transparent to the EJB Container.

  • Implementation class inheritance. It is possible to take advantage of the Java class implementation inheritance mechanism for the enterprise bean class. For example, the class CheckingAccountBean class can extend the AccountBean class to inherit the implementation of the business methods.

So the specification seems to give quite a bit of latitude to tools and container implementers when it comes to how to implement component inheritance between EJBs. It is good to keep this in mind when we look at the implementation of EJB inheritance in WAS AE 5.0 and WSAD 5.0. The development teams of these products have sought to create a sensible, consistent implementation of both interface inheritance and implementation class inheritance, while staying within the context of the specification. They have taken upon themselves to defining some aspects of component inheritance. This has proven to be challenging, but, as we will see, it has been possible.

1 Interface Inheritance for Sessions and Entities

Perhaps the easiest inheritance feature to understand is the direct support for inheritance of methods defined in local interfaces. For instance, what if in our Timekeeping example system we need to add subclasses of our EmployeeEJB as shown in Figure.

18. Interface inheritance between EJB local interfaces.

graphics/25fig18.gif

Our goal here is to have two subclasses of EmployeeEJB—SalariedEmployee and HourlyEmployee, with each type of Employee being paid differently. The first task is to define how the local interfaces (which specify the externally available methods of the entity) are related. This turns out to be just as simple as you might think, as the following two code snippets show (from now on, we'll only deal with one of the subclasses for the sake of space):





public interface EmployeeEJB extends javax.ejb.EJBLocalObject {

...

}



public interface SalariedEmployee extends EmployeeEJB {

...

}

In WSAD and WebSphere, any local interface can inherit from any other local interface, so long as the entire tree is rooted in javax.ejb.EJBLocalObject. The part that is more interesting than inheriting local interfaces (which, as we saw, were clearly defined in the specification) is in the inheritance of bean implementations that realize those interfaces.

Figure shows how inheritance is used in WebSphere and WSAD. While the example is that of an entity EJB, the principles discussed apply just as well to session beans. This figure is showing inheritance of just the local interfaces but the same is also true for the remote interfaces.

19. EJB inheritance.

graphics/25fig19.gif

As you can see, there is a parallel hierarchy of EJB implementation classes to match that of the local interfaces. The following two code snippets show how this is done:





public class EmployeeEJBBean implements EntityBean {

...

}





public class SalariedEmployeeBean extends EmployeeEJBBean {

...

}



The implementation of the subclass entity bean within WSAD will contain only the methods to support the cmp-fields defined for the bean plus the bean life cycle methods (e.g., ejbRemove(), ejbStore(), etc.). It will not contain any ejbCreate(…) or ejbPostCreate(…) methods since these methods are defined in one of the superclasses.

There are a few rules that govern EJB inheritance in both WSAD and WebSphere:

  • Entity bean implementations cannot inherit from session bean implementations and vice versa.

  • You cannot mix and match stateless and stateful session beans with session bean implementations—the type of the parent must match the type of all of its descendants.

  • A child entity bean must have the same client views as the parent entity bean. This means that you cannot have a child entity with both a remote and local client view that extends another entity bean with only a local client view.

2 Building Inherited Beans in WSAD

Now that we've seen what inheritance of local interfaces and bean implementations look like in EJBs, we can understand the support that WSAD provides developers in building EJBs with these relationships. To create an entity bean that inherits from another entity bean, you need to first open the EJB creation wizard by selecting the EJB module from the J2EE Hierarchy view and then select New > Enterprise Bean from the context menu. This first page is prefilled with the selected EJB project (i.e., TimeSheetGroup). The second page is shown in Figure.

20. Definition of SalariedEmployee CMP bean.

graphics/25fig20.jpg

The third page, Figure, is where you define the client view, the bean class name, cmp-fields, and the bean supertype. Notice that the key class defaults to that of the selected Bean supertype and it cannot be changed because all beans within the inheritance structure must share the same key class definition. Also, on the last page of the wizard you can define the bean superclass. This entry field is also preselected to the bean class of the selected bean supertype and you cannot change this value.

21. Defining the bean supertype.

graphics/25fig21.jpg

After selecting Finish, the entry in Listing 25.4 is added to the deployment descriptor.

SalariedEmployee definition in the deployment descriptor

<entity id="SalariedEmployee">

  <ejb-name>SalariedEmployee</ejb-name>

  <local-home>com.wsbook.casestudy.ejb.SalariedEmployeeLocalHome</local-home>

  <local>com.wsbook.casestudy.ejb.SalariedEmployeeLocal</local>

  <ejb-class>com.wsbook.casestudy.ejb.SalariedEmployeeBean</ejb-class>

  <persistence-type>Container</persistence-type>

  <prim-key-class>java.lang.String</prim-key-class>

  <reentrant>False</reentrant>

  <cmp-version>2.x</cmp-version>

  <abstract-schema-name>SalariedEmployee</abstract-schema-name>

  <cmp-field>

    <field-name>empId</field-name>

  </cmp-field>

  <cmp-field>

    <field-name>name</field-name>

  </cmp-field>

  <cmp-field>

    <field-name>office</field-name>

  </cmp-field>

  <cmp-field>

    <field-name>yearlySalary</field-name>

  </cmp-field>

  <primkey-field>empId</primkey-field>

  <ejb-local-ref id="EJBLocalRef_1047267616925">

    <ejb-ref-name>ejb/AddressEJB</ejb-ref-name>

    <ejb-ref-type>Entity</ejb-ref-type>

    <local-home>com.wsbook.casestudy.ejb.AddressEJBHome</local-home>

    <local>com.wsbook.casestudy.ejb.AddressEJB</local>

    <ejb-link>AddressEJB</ejb-link>

  </ejb-local-ref>

  <ejb-local-ref id="EJBLocalRef_1047267616935">

    <ejb-ref-name>ejb/TimeSheetEJB</ejb-ref-name>

    <ejb-ref-type>Entity</ejb-ref-type>

    <local-home>com.wsbook.casestudy.ejb.TimeSheetEJBHome</local-home>

    <local>com.wsbook.casestudy.ejb.TimeSheetEJB</local>

    <ejb-link>TimeSheetEJB</ejb-link>

  </ejb-local-ref>

</entity>

Notice there is more in this entry than you defined in the wizard. All of the entries in bold face have been copied from the bean supertype. This is done to satisfy the specification, and it allows the deployment descriptor to remain portable.

After an EJB is created, you can change its EJB inheritance structure at anytime by using the EJB deployment descriptor editor. On the Overview page of the editor, there is an inheritance section which is a part of the larger WebSphere Extensions section since this is not supported by the EJB specification. To change the EJB inheritance, select the desired EJB from the list and click the Edit button. This will open an Edit inheritance hierarchy wizard that will allow you to select the Inherits from supertype option which allows you to select another valid EJB from the module to inherit from or you can select the Does not inherit (make root) option that will remove the selected EJB from the current inheritance structure. If you select the second option, you will need to define a new key class for container-managed entities. This wizard will not only change the inheritance of your EJB but it will also refactor the Java classes so that the proper Java inheritance is in place after the edit. Also, the proper key class and create methods will be propagated appropriately.

3 Inheritance of Home Interfaces

At this point, inheritance of home interfaces cannot be supported while maintaining compliance with the EJB specification. As the EJB 2.0 FAQ suggests, this is mostly due to the required method signatures for find by primary key methods. Each home interface must include a method findByPrimaryKey(Key inKey) which returns an instance of its EJB class. If a parent class and subclass tried to define these methods, a signature conflict would be created in the subclass.

For example:





public interface EmployeeEJBHome extends javax.ejb.EJBLocalHome {

EmployeeEJB findByPrimaryKey(String primaryKey)...;

}

public interface SalariedEmployeeHome extends EmployeeEJBHome {

SalariedEmployee findByPrimaryKey(String primaryKey);

}

Method SalariedEmployeeHome.findByPrimaryKey cannot override the superclass method based on return type only because this would result in ambiguous method invocations in Java. Even though the home interfaces and implementations do not have a formal inheritance relationship, they do participate in the implementation of the inheritance of their EJB classes. When a user defines a generalization relationship, the expectation is that the members of that relationship may be instances of the root class or any of its subclasses. In order to satisfy this requirement, the finders on homes in inheritance hierarchies will answer a mixed collection containing instances of the root EJB class and its subclasses.

4 Database Inheritance Strategies

Now that we've investigated what it means for an EJB to inherit from another EJB, we have to address a second question that arises in the context of an entity EJB: How are generalization relationships preserved in the database that makes up the bean's persistent store?

There are two different schemes by which inheritance can be represented in a relational database. These schemes and their relative advantages and disadvantages have been described at length in [Fowler], and Chapter 14. The two schemes are:

  • Single-table inheritance— by which all the attributes of all of the classes in a hierarchy are stored in a single table, with special SQL select statements taking out only those attributes that are appropriate for any particular class.

  • Root-leaf inheritance— in which each class in a hierarchy corresponds to a table that contains only those attributes actually defined in that class, plus the key columns that are shared by all members of the hierarchy. An n-way SQL join is required to assemble any particular instance of a class from its corresponding table and all the tables above it in the inheritance hierarchy.

The major advantage of the first scheme is speed, while its major disadvantage is the size of the table (i.e., the number of null columns). The major advantage of the second scheme is its close correspondence to the object model, while its major disadvantage is the time it takes to do the necessary joins.

5 Mapping an EJB Inheritance Structure

Both of the inheritance schemes mentioned are supported in WSAD for container-managed entities to one degree or another. Which scheme a programmer chooses depends on balancing the benefits and liabilities in the context of how their application uses the data.

In Chapter 24, the EJB to RDB mapping wizard was first introduced to produce a top-down mapping. The top-down mapping options wizard page in Figure indicates that there are advanced options if there is an inheritance structure but in Chapter 24 the example did not use inheritance. The Next button on this wizard page is only enabled if EJB inheritance is used among the container-managed entities.

The last page, shown in Figure, will display each inheritance structure within the EJB module. By default, a single-table inheritance strategy is employed when doing a top-down mapping. You can override the default to root-leaf inheritance by selecting container-managed entities on this page. Each container-managed entity that is selected will have its own table generated for it, and a foreign key pointer will be added that joins to the parent table (i.e., the table that is mapped to the root container-managed entity in the inheritance).

22. Advanced top-down mapping options.

graphics/25fig22.jpg

Notice that you can mix both root-leaf inheritance and single-table inheritance strategies using this page. This is done by selecting some of the entities and not others. This may be a desired outcome if you have some of the entities with very few cmp-fields so it is more efficient to have those entities mapped with a single table inheritance strategy while other entities have many cmp-fields and would require their own table.

In a bottom-up mapping approach in which container-managed entities are generated from the columns and tables available in a database schema, inheritance cannot be reliably inferred from a database schema, so no inheritance mapping is applied by default. This is why you get one container-managed entity created for each database table that is defined. However, in the meet-in-the-middle mapping approach, where schema and EJB design are developed independently and then mapped into each other, both inheritance schemes are supported.

To map a child entity to one or more database tables, you would use the same mapping tools to create a mapping from the EJB to the database table. For example, if we use our SalariedEmployee example, we could create a mapping from the SalariedEmployee entity to the EMPLOYEEEJB table.

First we need to look at how the EMPLOYEEEJB table is defined. It will contain a new discriminator column which is used to store a string value that will be inserted as a value in the database row that is unique for each entity in the inheritance structure. This is used when reading a row from the database so the correct type of entity is instantiated. Figure shows the properties for the mapping of the EmployeeEJB to the EMPLOYEEEJB table. Notice that you must select a discriminator column and a discriminator value. Only the root entity will have the discriminator column but all mappings to each entity in the inheritance will require a discriminator value which automatically defaults to the name of the entity. The discriminator column is used to uniquely distinguish each subtype in the database.

23. Properties for root entity mapping.

graphics/25fig23.jpg

When you add the mapping from SalariedEmployee to EMPLOYEEEJB, a single-table inheritance mapping strategy is set up. This requires a discriminator value to be defined for this mapping (Figure).

24. Properties for a single-table inheritance mapping.

graphics/25fig24.jpg

Now, if you want to use a root-leaf inheritance strategy, you would need to map the SalariedEmployee to another table (e.g., SALARIEDEMPLOYEE). Now you can map the cmp-fields from SalariedEmployee to columns on the SALARIEDEMPLOYEE table. The properties for this mapping are slightly different than that for a single-table inheritance strategy. Figure shows the properties for a root-leaf inheritance mapping. The difference is that this mapping requires a join key to be defined. This is a foreign key on the SALARIEDEMPLOYEE table that joins it to the EMPLOYEEEJB table.

25. Properties for a root-leaf inheritance mapping.

graphics/25fig25.jpg

6 Wrapping Up EJB Inheritance

We don't have a good reason to employ EJB inheritance in the TimeSheet management case study application. Most cases for EJB inheritance stem from having inheritance in the Object model and wanting this directly reflected in your EJB implementation, particularly where there is benefit to the root home interface finder methods returning heterogeneous collection of EJBs. The other big benefit of object inheritance in general, decoupling between client type dependence and runtime type implementation, is supplied with all EJBs through the two local interfaces.


     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows