13.1 Single Inheritance of IDL Interfaces
As an example of single inheritance, consider extending the bank account example of Chapter 6, with checking (or current) accounts:
// IDL // In for example, "bank.idThe new interfacel".
// A bank account. interface Account { readonly attribute float balance; void makeDeposit(in float f); void makeWithdrawal(in float f); }; // Derived from interface Account.
interface CheckingAccount : Account { readonly attribute float overdraftLimit; // No new operations in this example.
}; interface Bank { exception Reject { string reason; }; Account newAccount( in string name) raises (Reject); void deleteAccount(in Account a); // An extra operation: CheckingAccount newCheckingAccount( in string name, in float limit) raises (Reject); };
CheckingAccount
derives from interface Account
. We have also added a new operation to interface Bank
, to manufacture CheckingAccount
s.1
13.1.1 The Client: IDL Generated Types
As in previous chapters, we will assume that this IDL definition has been compiled with the command:
idl -jP idl_demo bank.idlOrbixWeb maps IDL interfaces to Java interfaces. The IDL interface inheritance hierarchy maps directly to the Java interface inheritance hierarchy, as shown in Figure 13.1:
|
The interface
Account
maps to the following Java interface type:
// Java // Automatically generated // in file _AccountRef.java. package idl_demo; public interface _AccountRef extends IE.Iona.Orbix2.CORBA._ObjectRef { public float balance() throws IE.Iona.Orbix2.CORBA.SystemException; public void makeDeposit(float f) throws IE.Iona.Orbix2.CORBA.SystemException; public void makeWithdrawal(float f) throws IE.Iona.Orbix2.CORBA.SystemException; }The IDL interface
CheckingAccount
maps to:
// Java // Automatically generated // in file _CheckingAccountRef.java. package idl_demo; public interface _CheckingAccountRef extends idl_demo._AccountRef, IE.Iona.Orbix2.CORBA._ObjectRef { public float overdraftLimit() throws IE.Iona.Orbix2.CORBA.SystemException; }The IDL compiler also generates Java implementation classes for these Java interfaces2. For each Java interface, the corresponding class implements the methods defined in the interface. Each method implementation provides client proxy functionality for the appropriate IDL operation. The Java class also implements static
_bind()
and _narrow()
methods.
IDL interface inheritance maps directly to the inheritance hierarchy of the generated Java interfaces, but does not map to the generated Java classes for those interfaces. Therefore, each Java class which implements an IDL generated Java interface must implement both the methods of that interface and the methods of all interfaces from which it inherits. Of course, this is an internal OrbixWeb implementation detail and does not impose any additional burden on the programmer.
The generated Java class which implements the
_AccountRef
interface is:
// Java // Automatically generated // in file Account.java. package idl_demo; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.CompletionStatus; public class Account extends IE.Iona.Orbix2.CORBA.BaseObject implements idl_demo._AccountRef { public float balance() throws IE.Iona.Orbix2.CORBA.SystemException { ... } public void makeDeposit(float f) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public void makeWithdrawal(float f) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public IE.Iona.Orbix2.CORBA._sequence_String _baseInterfaces() { ... } public static final idl_demo._AccountRef _bind() throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._AccountRef _bind(String markerServer) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._AccountRef _bind(String markerServer, String host) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._AccountRef _narrow(IE.Iona.Orbix2.CORBA._ObjectRef src) throws IE.Iona.Orbix2.CORBA.SystemException { ... } ... }The generated Java class which implements the
_CheckingAccountRef
interface is:
// Java // Automatically generated // in file CheckingAccount.java. package idl_demo; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.CompletionStatus; public class CheckingAccount extends IE.Iona.Orbix2.CORBA.BaseObject implements idl_demo._CheckingAccountRef { public float overdraftLimit() throws IE.Iona.Orbix2.CORBA.SystemException { ... } public float balance() throws IE.Iona.Orbix2.CORBA.SystemException { ... } public void makeDeposit(float f) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public void makeWithdrawal(float f) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._CheckingAccountRef _bind() throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._CheckingAccountRef _bind( String markerServer) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._CheckingAccountRef _bind( String markerServer, String host) throws IE.Iona.Orbix2.CORBA.SystemException { ... } public static final idl_demo._CheckingAccountRef _narrow(IE.Iona.Orbix2.CORBA._ObjectRef src) throws IE.Iona.Orbix2.CORBA.SystemException { ... } ... }
CheckingAccount
s in a similar way to the Account
s of Chapter 6:
// Java // In file Client.java. package idl_demo; import IE.Iona.Orbix2.CORBA.SystemException; public class Client { public static void main (String args[]) { _BankRef bRef; _AccountRef aRef; _CheckingAccountRef cRef; try { // Bind to any bank object in the // BankSrv server. bRef = Bank._bind (":BankSrv"); // Obtain a new bank account. aRef = bRef.newAccount ("Chris"); aRef.makeDeposit ((float) 56.90); } catch (idl_demo._Bank.Reject re) { System.out.println ( "Error on newAccount():"); System.out.println ( "Account creation rejected " + "with reason: " + re.reason); return; } catch (SystemException se) { System.out.println ( "Unexpected system exception:"); System.out.println (se.toString ()); return; } try { // Obtain a new checking account. cRef = bRef.newCheckingAccount ("Susie", (float) 100.00); cRef.makeDeposit ((float) 87.78); } catch (idl_demo._Bank.Reject re) { System.out.println ( "Error on newCheckingAccount():"); System.out.println ( "Account creation rejected " + "with reason: " + re.reason); return; } catch (SystemException se) { System.out.println ( "Unexpected system exception:"); System.out.println (se.toString ()); return; } } }For information on narrowing object references in an inheritance hierarchy, see section 5.9.1.
13.1.3 The Server: IDL Generated Types
On the server side, the IDL compiler generates the Java interface _CheckingAccountOperations
, which defines the methods that a server class must implement in order to support IDL interface CheckingAccount
. This Java interface inherits from type _AccountOperations
, which serves a similar purpose for IDL type Account
. The manner in which a Java class implements the _CheckingAccountOperations
method depends on the approach to IDL interface implementation in use. The BOAImpl Approach
The IDL compiler generates class _boaimpl_CheckingAccount
to support the BOAImpl approach to IDL interface implementation. This abstract class implements Java interface _CheckingAccountOperations
and redefines the methods of that interface (and all interfaces from which it inherits) as abstract methods. CheckingAccount
using the BOAImpl approach, the programmer defines a Java class which inherits from class _boaimpl_CheckingAccount
and implements the methods defined in this class. This has important consequences for the reusability of implementation classes. CheckingAccount
(for example, an existing class implements IDL type Account
), it cannot be reused in the CheckingAccount
implementation class. The CheckingAccount
implementation class must directly implement all the operations of IDL interface CheckingAccount
and all interfaces from which it inherits. This restriction severely limits the flexibility of the BOAImpl approach.Account
and CheckingAccount
could be implemented as follows:
// Java // In file AccountImplementation.java. package idl_demo; public class AccountImplementation extends _boaimpl_Account { // Methods and variables to implement // interface Account. As before. ... } // Java // In file CheckingAccountImplementation.java. package idl_demo; ... // Note - cannot inherit Account implementation, // so we must reimplement the methods for type // Account. public class CheckingAccountImplementation extends _boaimpl_CheckingAccount { // Reimplement all methods and variables // defined in class AccountImplementation. // As before. ... // Implement new methods and variables // for CheckingAccount. float m_limit; public currentAccountImpl () throws SystemException { // Details omitted. } public currentAccountImpl (float initialBalance, String name, float limit) throws SystemException{ // Details omitted. } // Method for new IDL attribute public float _get_overdraftLimit () { return m_limit; } }
CheckingAccount
implementation class simply needs to implement Java interface _CheckingAccountOperations
; that is, there is no implicit inheritance requirement imposed on the implementation class. This has the advantage of making the implementation programmer free to inherit from any existing class which may implement a subset of the required methods.For example, if existing class
AccountImplementation
implements the methods defined in interface _AccountOperations
, then class CheckingAccountImplementation
could be coded as follows:
// Java // In file CheckingAccountImplementation.java. package idl_demo; ... // Note - inherit Account implementation, // so we do not need to reimplement the methods // for type Account. class CheckingAccountImplementation extends AccountImplementation, implements _CheckingAccountOperations { float m_limit; public currentAccountImpl () throws SystemException { // Details omitted. } public currentAccountImpl (float initialBalance, String name, float limit) throws SystemException{ // Details omitted. } // Method for new IDL attribute. public float _get_overdraftLimit () { return m_limit; } }The TIE approach allows the programmer to take advantage of the re-use characteristics of object-oriented programming.
// IDL // In for example, "bank.idlJava also supports multiple inheritance of interfaces, but does not support multiple inheritance of classes. As in the case of single inheritance, the inheritance hierarchy of IDL interfaces maps directly to an identical inheritance hierarchy of Java interfaces which define client-side functionality. For example, the interface hierarchy in the above definition maps as follows:".
// A bank account. interface Account { readonly attribute float balance; void makeDeposit(in float f); void makeWithdrawal(in float f); }; // Derived from interface Account.
interface CheckingAccount : Account { readonly attribute float overdraftLimit; }; // Derived from interface Account.
interface DepositAccount : Account { }; // Indirectly derived from interface Account.
interface PremiumAccount : CheckingAccount, DepositAccount { };
|
The inheritance hierarchy does not map to the Java classes which implement the generated Java interfaces. Consequently, each generated Java class implements the methods of the corresponding Java interface and of all interfaces from which it inherits. In this way, a client which holds
_PremiumAccountRef
object reference can invoke all inherited operations (from _AccountRef
, _CheckingAccountRef
, and _DepositAccountRef
) directly on that reference.On the server side, the implementation class requirements are identical to those for the single inheritance case. Using the BOAImpl approach, the implementor of type
PremiumAccount
must inherit from class _boaimpl_PremiumAccount
and directly implement all methods for interface PremiumAccount
and all types from which it inherits. Using the TIE approach, the implementation class must implement Java interface _CheckingAccountOperations
, but may inherit implementation methods from an existing class. However, the absence of multiple inheritance support in Java implies that a multiple inheritance hierarchy of IDL interfaces can never map directly to the implementation classes for those interfaces.Note that IDL forbids any ambiguity arising due to name clashes of operations and attributes when two or more direct base interfaces are combined. That is, it is illegal for an IDL interface to inherit from two or more interfaces with the same operation or attribute name. It is, however, legal to inherit two or more constants, types or exceptions with the same name from more than one interface, however every use of these must be qualified with the name of the interface (that is, an IDL scoped name must be used).
Bank
, for example, to produce a new interface, say, commercialBank
, which supports the newCheckingAccount
operation. However, this would have made the example a little more difficult to explain.