Check out the new USENIX Web site. next up previous
Next: Per-Process Filters Up: Problems Previous: Problems

   
CORBA Inheritance Issues

This problem arose because COPE piggybacks references to assumption objects, and it is common to derive specific kinds of assumptions from the assumption class. It is always somewhat complex figuring out how to implement a CORBA-based program using a specific ORB, but figuring out how to structure COPE was especially hard. It took approximately a month of mail exchange with Iona before the problem was understood well enough to resolve.

Most ORBs are implemented using an object-oriented language, such as Java or C++. A CORBA-based application is defined, in IDL, as a set of classes that may be related via single inheritance. The IDL compiler translates these inheritance relations in some manner into a set of class definitions in the implementation language. Consider a CORBA class Bar that inherits from a CORBA class Foo. The implementation object (say, BarImpl) should also inherit from the implementation object FooImpl. In addition, with most IDL compilers both implementation objects are instances of a base CORBA object class.

The problem discussed here is concerned with the translation chosen by the OrbixWeb IDL compiler.1 Before discussing the problem further, we provide some background concerning how objects are implemented in OrbixWeb. Suppose we have an IDL interface as follows:

  interface Foo {
     void foo_method();
  };

  interface Bar : Foo {
     void bar_method(Foo f);
  };

The OrbixWeb IDL compiler generates eight files for each CORBA interface. For example, the CORBA interface Foo is compiled into FooHolder, FooHelper, _FooSkeleton, _FooStub, _FooImplBase, _tie_Foo, _FooOperations, and Foo. The first two are helper classes that support marshalling, narrowing, and other CORBA support operations. The next two are classes that are placeholders for the stubs. The last four, two classes and two interfaces respectively, are described in more detail below.

The complete inheritance hierarchy for Foo is depicted in Figure 2. Rectangles represent interfaces. Shaded ovals and rectangles represent classes and interfaces provided in standard packages such as org.omg.CORBA. These packages are part of OrbixWeb core classes.


  
Figure 2: IDL-generated files for Foo
\begin{figure}\begin{center}
\leavevmode
\epsfxsize=3.25in
\epsfysize=1.75in
\epsfbox{foo_bar.eps}\end{center}\end{figure}

There are two approaches with which one can implement an OrbixWeb object: the ``ImplBase'' approach and the ``tie'' approach [4]. Suppose you wish to implement the CORBA class Foo with the Java class FooImpl. In the ImplBase approach, FooImpl has the following signature:

   public class FooImpl extends _FooImplBase
That is, FooImpl is a subclass of the class _FooImplBase. And, since _FooImplBase implements the Java interface Foo (See Figure 2), FooImpl also implements Foo. Therefore, a CORBA Foo object can be instantiated as follows:

   Foo foo = new FooImpl();

The tie approach, in contrast, is a delegation model. With this approach the FooImpl class implements the _FooOperations interface. However, since _FooOperations and Foo are both interfaces, to instantiate a CORBA Foo object one first instantiates a FooImpl instance and then instantiates a _tie_Foo instance with the FooImpl instance as a parameter:

   Foo foo = new _tie_Foo( new FooImpl() );
Since _tie_Foo implements Foo, the variable foo has type Foo as desired.

Now consider implementing the class Bar. One would naturally wish the implementation BarImpl to inherit from FooImpl. But, BarImpl also implements the methods declared in the CORBA Bar class. As was done in implementing Foo, we can use either the ImplBase approach or the tie approach. However, the ImplBase approach requires BarImpl inheriting from _BarImplBase. This implies multiple inheritance of classes, which Java does not support. Thus, one is constrained to use the tie approach, viz.:

   public class BarImpl extends FooImpl
      implements _BarOperations

Since we are using the tie approach, an instance of Bar is created by wrapping an instance of BarImpl in an instance of _tie_Bar:

   Bar bar = new _tie_Bar( new BarImpl() );
Figure 3 illustrates the resulting inheritance diagram of a FooImpl object and a BarImpl object.


  
Figure 3: Inheritance Diagram
\begin{figure}\begin{center}
\leavevmode
\epsfxsize=3.25in
\epsfysize=1.25in
\epsfbox{bar.eps}\end{center}\end{figure}

The problem with the tie approach, however, is that the implementation objects (FooImpl and BarImpl in this example), are not instances of the Java interface that represents the CORBA object (Foo and Bar in this example). This poses a problem when using CORBA operations.

For example, suppose that there is a CORBA Bar object B1 on processor 1 and a CORBA Bar object B2 on processor 2. B2 has a reference r to B1, and invokes the method r.bar_method(this).

Further suppose that the implementation of bar_method in BarImpl tests the parameter f to see if it is an instance of Bar:

1  public bar_method (Foo f) {
2    if (f instanceof Bar) 
3       ...
4    else
5       ...
     }
One might expect that the code in Line 3 would be executed, but it is not due to an implementation decision by Iona. While marshalling this on B2, CORBA determines the class of the value it is marshalling through a method on it named type, e.g., it invokes this.type(). If this were to implement the Java interface Bar, then this.type() would return a value indicating the CORBA class Bar. But, since this implements _BarOperations, this.type() returns the value null. The marshalling code therefore declares the parameter passed in the message to B1 to be of type reference to Foo.

We dealt with this problem in the manner recommended by Iona. We save in the Java implementation of every CORBA object a reference to the tie object. For example, let the member variable referring to the tie object of an instance of Bar be tieObject. The declaration of tieObject and the constructor in the definition of the class BarImpl can be as follows:2

public class BarImpl
  implements _BarOperations {
  protected Bar tieObject; // declaration

  BarImpl() {
     ...
     tieObject = new _tie_Bar( this );
     }
  }
Then, B2 invokes r.bar_method(tieObject) instead of r.bar_method(this). Since tieObjects implements Bar, tieObject.type() returns a value indicating the CORBA class Bar.

This problem occurs in other situations. It is in general a good OrbixWeb design practice to have objects like BarImpl implement a method that returns a reference to the tie object. This reference should be used in all places where a reference to the implementation is passed using CORBA.

This additional complexity in structure can be avoided by enforcing a file naming structure on the user's code. For example, some IDL compilers generate a file that the user edits to include the Java implementation of the CORBA object. Unlike OrbixWeb, the IDL compiler knows the name of the implementation class when it generates the files. Hence, the IDL compiler can generate files that explictly inherit from this class as needed. In our example, if the IDL compiler names the implementation class for Foo as FooObj, then the implementation class for Bar might be generated as

   public class BarObj
      extends FooObj
      implements _BarOperations


next up previous
Next: Per-Process Filters Up: Problems Previous: Problems

1999-03-21