Java Mapping for CORBA

Xerox Corporation Initial Submission

January 10, 1997

Copyright (c) 1996, 1997 Xerox Corporation. All Rights Reserved.
(Full copyright notice at the end.)

Table of Contents


Introduction

This document describes the mapping of OMG IDL constructs to Java constructs.

This document is still being changed frequently
Please send comments to:

[email protected]

This document is not complete. We anticipate changes to improve compatibility with other vendors.

Items not yet addressed by this mapping are, DII, DSI and IDL Type Extensions.
We have no mapping for the concept of IDL Context's.

This document does not describe the exact mapping generated by a stubber. This document exhibits a nominal mapping, which is detailed enough for application programmers to use. An application is conformant when it works with the nominal mapping. A stubber is conformant when when it emits Java that works with any conformant application.

Rationale

We try to run a fine balance between being natural for Java programmers, being in the spirit of CORBA, supporting different kinds of ORBs, while being as simple as possible. These goals compete; we believe we have provided a good compromise.


Naming Issues

Package name

This document is written as if all OMG defined classes and interfaces are in a package CORBA.

The actual name of this package is not a part of this submission, but we hope that the issue will be resolved in the actual OMG standard.
Available Java documentation provides mixed and inconsistent messages about package names. We do not dare predict whether the OMG will follow the painful and inconsistently used DNS naming convention; i.e, name their package COM.omg.corba. More likely the OMG might state that CORBA is a standard and is not likely to cause conflicts; consequently the package name would be simply CORBA.

Rationale

We desire short names which make applications easy to read while still keeping track of where names are coming from; we do not like a style which opens up all members with ``import foo.*'' as we are concerned programmers might not be aware of all identifiers opened up.

We have considered a design where all required classes are named with a prefix ``corba_''. The Java import with a ``*'' does not support import of packages, only import of classes. By prefixing all classes we would enable the user to write an import statement like

import CORBA.*;
and opening up the corba package without fear of conflicts. We decided to ignore this issue and propose use of a short package name where programmers would not be tempted to use the import syntax with the asterisk. We view this limitation of the asterisk import to classes as a shortcoming in the Java language and urge removing this limitation in future versions of Java.

Other name suffixes and prefixes

There are some situations in which we have to build names composed of multiple parts i.e. FooBar and FooBar_stub. Typically the first part of a name has been given in IDL. The second part of a name describes the purpose of the Java name. We will separate the two parts of a name with a underscore as separator. We need to generate composite names to avoid name conflicts when multiple Java names arederived from one IDL name.

We only use a separator if we concatenate name pieces where one is defined by a programmer and the other is defined by this mapping.

Example

Anticipating some mappings:

/* From the IDL source: */
module Example {
	interface FooBar_Mumble { 
	...
	};
};
// Generated names in package myprefix.Example
	class FooBar_Mumble_stub ...
	interface FooBar_Mumble ...

Rationale

We admit that separators look ugly but we think using a separator will lead to code which ultimately is easier to read by programmers.

We believe that a consistent style which distinguishes composition according to whether it is coming from IDL or from the mapping might make programs easier to maintain.

The two main choices for the separator in mapping-defined compositions are underscore and the empty string. The underscore makes for a linguistically weaker binding, which combines more appropriately with IDL names that are themselves compositions of names in the problem domain. E.g., "alloc_bank_account" and "alloc_BankAccount" is a better set of choices than "allocbank_account" and "allocBankAccount".


Scoped Names

IDL nested scopes (not modules) are handled by concatenating the names and using a separator.

Example

/* IDL */
interface example0 {
    ...
    struct nest1 {
       ...
    }       
    ...
 };
maps to the Java classes example0 and example0_nest1.


Java Keywords

If an IDL name matches a Java keyword the stubber will prefix the name with an extra underscore.

This is likely to happen to user defined names only because for most IDL defined names the capitalization prevents conflicts with Java keywords.

We do not yet specify how we handle other name conflicts due to unlucky names in an IDL file.

Fine point

There are possible conflicts with names from Java packages because of the automatic import of java.lang. Such conflicts can be distinguished by not using the star syntax when importing CORBA. However several Java compiler seem to have a bug which causes this conflicts even without explicit import.


Modules

A module in IDL is mapped to a Java packages with the same name. The Java package tree is isomorphic to the module tree in IDL save that a top-level package prefix may be specified in an implementation-dependent fashion. This top-level package prefix can be set independently for each IDL module.

For an IDL type declared in a particular module, the corresponding Java classes and interfaces are declared inside the Java package generated for that module.

IDL allows definitions outside the scope of modules. We strongly discourage use of such IDL.

The generated mapping is as if each module in the file were complete; re-opening is considered only for modules whose only direct elements are themselves modules.

Rationale

Some applications will have IDL modules with the right Java naming structure in mind, other applications start with application specific IDL module names. For the former applications the package prefix will be empty; the top level module will map into a top level package. For the later applications using a non-empty package prefix is safer and a means to avoid name conflicts with whatever is available in a Java programming environment.
Most examples in this document use a package prefix myprefix.


Constants

IDL const values are mapped to a Java class with public static final instances representing the value. The name for the class is the name of the IDL const; the instance variable is named value.

Example

/* From the IDL source: */
module Example {
	const float pi = 3.1415;	 
};
// Generated Java:
package myprefix.Example;
public final class pi {
    public static final float value = 3.1415;
}

A client of Example::pi would reference the value as

myprefix.Example.pi.value

Rationale

An alternative design could put all constants of a module into one specific Java class for constants from this module. We didn't choose that design because it wouldn't extend to reopened modules. Either design forces Java programmers to use one extra identifier when naming constants; the difference is whether the artificial identifier names a predefined class or whether it names a predefined member.


Basic Types

Boolean

The IDL type boolean is mapped to Java boolean.

Char

The IDL type char is mapped to the Java type char.

The Java type char which needs 16 bits can express characters which are not present in IDL's 8 bit character set. Characters which can't be represented cause a CORBA.CharacterRangeException exception or a subclass thereof to be thrown when marshalling. CORBA.CharacterRangeException is a subclass of CORBA.MARSHAL described later.

Octet

The IDL type octet is mapped to the Java type byte.

As the Java type byte contains a signed value from -128..127 the mapping will preserve equality modulo 256.

String

Both bounded and unbounded IDL string types are mapped to the Java type java.lang.String. Characters in the Java string which can't be represented as IDL characters cause an CORBA.CharacterRangeException exception, or a subclass thereof, to be thrown when marshalling.

Bounded IDL Strings are length checked when marshaling. Attempts to marshal or unmarshal bounded strings with a length exceeding the bound will cause a CORBA.LengthException exception or subclass thereof to be raised.

Integer Types

IDL integer types are mapped according to this table:
	IDL              Java     Number of bits
	short            short    16
	unsigned short   short    16
	long             int      32
	unsigned long    int      32

An anticipated 64-bit integer type would be mapped into long.

IDL unsigned data types are mapped into the very same data type as the corresponding signed data types. Numbers which can't be correctly represented because of a lacking bit are represented by their corresponding bit pattern assuming a two's complement implementation.

Floating Points

IDL float maps into Java float; IDL double maps into Java double.

If an ORB uses a representation that limits precision, it needs to be documented.


Constructed and Template Types

All generated Java classes which are defined in this section as a mapping from an IDL type are named like the IDL type.

Enum

An IDL enum type is mapped to the Java int type. Additionally, a Java class is generated to hold a static final int for each enum member. The class name is the name of the IDL enum type.

Example

/* From the IDL source: */
module Example {
	enum MyColor { white, red, blue, green };
};
// Generated Java:
package myprefix.Example;
public class MyColor {
    public static final int white = 0;
    public static final int red = 1;
    public static final int blue = 2;
    public static final int green = 3;
    public static final int narrow(int i) 
	throws CORBA.EnumerationRangeException /* or a subclass */ { ... }
}

The static narrow method either returns its input or throws an exception. It is used to verify that Java int's are in the range of the IDL enum.

Struct

An IDL struct is mapped to a Java class which has public instance variables for the fields. The class is named with the name of the IDL struct. It has a static method named alloc to create a new instance. The alloc method has one version that leaves fields unspecified and another version that initializes all fields.

Example

/* From the IDL source: */
module Example {
	struct StructExample {
		short mumble;
		string greeting;
	};
};
// Generated to java:
package myprefix.Example;
public class StructExample {
    public short mumble;
    public String greeting;
    public static StructExample alloc() { ... }
    public static StructExample alloc(short mumble, String greeting) { ... }
}

Rationale

This is the obvious implementation. If a programmer really wants accessor methods he can specify the IDL source accordingly. We use static methods to allocate instances as a matter of style to allow ORBs to subclass at a vendor's option.

Union

An IDL union is mapped to a Java class named with the name of the IDL union.

To construct values applications use one of the static allocation procedures which take both a discriminator value and a branch value. If the discriminator value is not legal for the chosen branch a CORBA.DiscriminantException exception or a subclass thereof is thrown. The allocation procedure is named after the branch with the prefix ``alloc_''.

The method discriminator returns the value of the discriminator.

The accessor method for a branch is named by the name of the branch with the prefix ``get_'' Attempts to call an accessor for other than the actual branch will throw a CORBA.DiscriminantException exception or a subclass thereof.

Example

/* From the IDL source: */
module Example {
	union UnionExample switch (MyColor) {
	case red:	long abc;
	case blue:	short efg;
	case green:
	default:	boolean xyz;
	};
};
// Generated Java:
package myprefix.Example;
public final class UnionExample {
    public int discriminator()
	throws CORBA.DiscriminantException /* or a subclass */ { ... }
    //	abc
    public int get_abc()
	throws CORBA.DiscriminantException /* ...*/ { ... }
    public static UnionExample alloc_abc(int discriminator, int value) 
	throws CORBA.DiscriminantException /* ...*/ { ... }
    //	efg
    public short get_efg()
	throws CORBA.DiscriminantException /* ...*/ { ... }
    public static UnionExample alloc_efg(int discriminator, short value)
	throws CORBA.DiscriminantException /* ...*/ { ... }
    //	xyz
    public boolean get_xyz() 
	throws CORBA.DiscriminantException /* ...*/ { ... }
    public static UnionExample alloc_xyz(int discriminator, boolean value) 
	throws CORBA.DiscriminantException /* ...*/ { ... }
}

Design variant

If unions were mutable, we would add the following paragraphs:

The allocation method alloc returns an union in an unknown state. A value is assigned with a setter named after the branch with the prefix ``set_''.
The setter methods take two arguments: a discriminator value and a branch value. If the discriminator value is not legal for the chosen branch a CORBA.DiscriminantException or subclass thereof is thrown. The setter methods returns the union.

Invoking accessor methods or the discriminator accessor, on uninitialized unions may throw an CORBA.DiscriminantException or could generate other Java runtime errors.

The following methods would be added to the example union class:


    public static UnionExample alloc() { ... }
    public UnionExample set_abc(int discriminator, int value) 
	throws CORBA.DiscriminantException /* ...*/ { ... }
    public UnionExample set_efg(int discriminator, short value) 
	throws CORBA.DiscriminantException /* ...*/ { ... }
    public UnionExample set_xyz(int discriminator, boolean value) 
	throws CORBA.DiscriminantException /* ...*/ { ... }

Marshaling will not modify union values but treat in arguments as readonly and allocate new unions for out or inout arguments.
Changing a union is not an atomic operation; however synchronization or single threaded usage is the clients responsibility.

Sequence

An IDL sequence is mapped to a Java array. Everywhere the sequence type is needed, an array of the element type is used.
Bounded sequences have their bounds checked when they are marshaled as parameters to IDL operations; a CORBA.LengthException exception, or a subclass thereof, is raised when the bounds are exceeded.
Exception: Sequences of characters are mapped to java.lang.String

Example

Recalling the mapping for IDL structs:

/* From the IDL source: */
module Example {
	struct BarSequenceCont {
		sequence< StructExample > ubs;
		sequence< StructExample, 17 > fls;
	};
};
// Generated Java:
package myprefix.Example;
public final class BarSequenceCont {
    public myprefix.Example.StructExample[] ubs;
    public myprefix.Example.StructExample[] fls;
    public static BarSequenceCont alloc() { }
    public static BarSequenceCont alloc(myprefix.Example.StructExample[] ubs, 
			     myprefix.Example.StructExample[] fls) { ... }
}

Note: The mapping does not prescribe any Java class for sequences. This means that no client visible operations needs such a class; it does not imply that an ORB couldn't use such a class for internal reasons.

Rationale

Bounded and unbounded sequences are treated the same way by the programmer.

Array

An IDL array is mapped to a Java array. Everywhere the array type is needed, an array of the element type is used. The bounds are checked when marshaling and a CORBA.LengthException exception, or a subclasst thereof, is raised when the bounds do not match.
The length of an array is not directly available as a constant. IDL modules designed with Java in mind will typically define an IDL constant if this number is desired.

Example

/* From the IDL source: */
module Example {
	const long count = 17;
	struct FooStruct {
		long	fooarray[count];
	};
};
// Generated Java:
package myprefix.Example;
public final class FooStruct {
    public int[] fooarray;
    public static FooStruct alloc() { }
    public static FooStruct alloc(int[] fooarray) { ... }
}

Rationale

This is the same mapping as sequences.


ILU-style Optionals

If ILU-style Optionals are ever adopted into the OMG IDL type system they will be mapped as follows:

If the base type of the optional maps into a Java primitive type we will represent the optional with the corresponding Java wrapper or container class. (Boolean, Character, Double, Float, Integer, or Long). The null value represents absence of the parameter.

If the base type of the optional maps into a Java object type, the optional is mapped as if it weren't optional. The null value represents absence of the parameter.

In the case of Java Strings the difference between a null String and an empty string serves this distinction perfectly.


Type Declaration (typedef)

Note: We are confused about the meaning of IDL typedefs; in particular we don't know for sure whether an IDL typedef defines an alias for an identical type, or a different type with the same structure; this mapping has been designed assuming a typedef means an alias. This issue has been referred to the OMG architecture board.

Java has no concept for renaming a class. We ignore a typedef'ed name and ask the programmer to use its definition instead.

Rationale

We have considered using subclasses instead. However subclasses and superclasses can only be assigned in one direction; a limitation which we would consider too severe. Typedefs would be good candidate for a Java language change.


Exceptions

All exceptions are subclasses of CORBA.Exception. All mentioned exceptions thrown are subclasses of either CORBA.SystemException or CORBA.UserException, which are both subclasses of CORBA.Exception.

The ORB is always allowed to raise subclasses of the exception specified to be raised.

The Java class CORBA.Exception follows:

package CORBA;
public class Exception extends java.lang.Exception {
    // may extend a subtype of java.lang.Exception instead
    
    // CORBA defined exception types.
    static public final int noException = 0;
    static public final int userException = 1;
    static public final int systemException = 2;

    // Accessors
    public int exceptionType() ...
    public String exceptionId() ...
}

Note that there may be no public constructor.
It is a convention in Java that all subclasses of Throwable have two specific constructors. Most ORB's will honor this convention but the constructors may be declared off limits to users.

The exceptionId method returns the repository identifier for the exception.

Standard Exceptions

The IDL defined exceptions have corresponding Java exceptions. All Java exceptions from the mapping of IDL defined system exceptions are (direct or indirect) subclasses of the CORBA.SystemException exception. CORBA.SystemException is a (direct or indirect) subclass of CORBA.Exception.

The standard system exceptions allow access to the minor code and completion status for the exception. All standard system exceptions are (maybe indirect) subclasses of CORBA.SystemException, shown here:

package CORBA;
public class SystemException extends CORBA.Exception {
    // may extend a subtype of CORBA.Exception instead
    
    //	Completion status constants.
    static public final int completedYes = 0;
    static public final int completedNo = 1;
    static public final int completedMaybe = 2;
    
    //	Accessors
    public int completed() { ... }

    public int minor() { ... }
    

}

There should be no public constructors for CORBA.SystemException. Applications should instantiate subclasses only.

The IDL standard system exceptions are mapped to the Java classes:

CORBA.UNKNOWN
CORBA.BAD_PARAM
CORBA.NO_MEMORY
CORBA.IMP_LIMIT
CORBA.COMM_FAILURE
CORBA.INV_OBJREF
CORBA.NO_PERMISSION
CORBA.INTERNAL
CORBA.MARSHAL
CORBA.INITIALIZE
CORBA.NO_IMPLEMENT
CORBA.BAD_TYPECODE
CORBA.BAD_OPERATION
CORBA.NO_RESOURCES
CORBA.NO_RESPONSE
CORBA.PERSIST_STORE
CORBA.BAD_INV_ORDER
CORBA.TRANSIENT
CORBA.FREE_MEM
CORBA.INV_IDENT
CORBA.INV_FLAG
CORBA.INTF_REPOS
CORBA.BAD_CONTEXT
CORBA.OBJ_ADAPTER
CORBA.DATA_CONVERSION
CORBA.OBJECT_NOT_EXIST

As with CORBA.SystemException the constructors may be private and should not be used by applications. Instead of using a constructor, a static allocation method is provided for use by applications.

One allocation method requires default values for the minor code and completion status; another allocation method supplies default values. .

As an example, CORBA.UNKNOWN is declared to include:

package CORBA;
public class UNKNOWN extends CORBA.SystemException {
    public static UNKNOWN alloc() {...}
    public static UNKNOWN alloc(int minor, int completed) {...}
}
This mapping document describes also a few exceptions that are subclasses of standard system exceptions. For example CORBA.CharacterRangeException, CORBA.LengthException, CORBA.EnumerationRangeException and CORBA.DiscriminantException are subclasses of CORBA.BAD_PARAM or a subclass thereof.

Rationale

We were contemplating exception names which are more natural to the Java programmer. However since some of the actual exceptions are unfamiliar to Java programmers and not all ORBs will throw all defined exceptions we thought that a natural relationship to the IDL definition might be easier to manage by the programmer.

We have considered making CORBA.EnumerationRangeException and CORBA.DiscriminantException subclasses of java.lang.RuntimeException. In that case they would have been runtime errors and therefore methods which were declared to throw those exceptions could be used outside the scope of try-catch statements. It was a close call whether this benefit outweighs the conceptional cost of explain which exceptions are and which are not subclasses of CORBA.Exception. It would even be possible for ORBs to catch these runtime errors at marshal or unmarshal time and rethrow corresponding CORBA.SystemExceptions.

User Exceptions

IDL user-defined exceptions are mapped similarly to IDL structs. A Java class is generated that provides instance variables for the fields of the exception. The class has static methods to construct instances. One version of the allocator method requires no arguments; an overloaded version requires all the fields of the exception.

IDL user-defined exceptions extend the Java class CORBA.UserException (or a subclass thereof, which in turn extends CORBA.Exception which indirectly extends java.lang.Exception). This makes it possible to catch specific user-defined exceptions, to catch all user-defined exceptions by catching CORBA.UserException, or, to catch all user-defined exceptions and system exceptions by catching CORBA.Exception.

Example

/* From the IDL source: */
module Example {
	exception Barf {
		string because;
	};
};
// Generated Java:
package myprefix.Example;
public class Barf
	extends CORBA.UserException /*or a subclass*/ {
    public String because;
    public static Barf alloc() { ... }
    public static Barf alloc(String because) { ... }
}


Interfaces

An IDL interface is mapped to a Java interface of the same name. Also generated are a stub class, and optionally a skeleton class to ease the implementation of true objects.

Interfaces and Object References

Operations on IDL interfaces are mapped to methods declared on the Java interface. The Java interface specifies the signatures of the operations directly defined in the IDL interface and inherits from the interfaces implementing inherited IDL interfaces.

Operations of the IDL class CORBA::Object are special; these operations are not implemented by a object reference interface but are implemented as static methods of an ORB specific class. See the section Methods on CORBA::Object for details.

Example

/* From the IDL source: */
module Example {
	interface MyIf {
		public void doit();
	};
};

We show the generated Java interface, which is named by the name of the IDL interface.

// Generated Java:
package myprefix.Example;
public interface MyIf
    extends CORBA.Object { //or a subinterface thereof
    void doit() throws CORBA.SystemException;
    
}

The Java interface extends the CORBA.Object Java interface.

IDL Interface Inheritance

IDL interface inheritance is mapped by the corresponding inheritance of the Java interfaces for the mapped IDL interface.

To model IDL multiple interface inheritance in Java we use multiple inheritance in the Java interfaces.

Example

This example shows a multiple inheritance lattice:

/* From the IDL source: */
module Example {
	interface Base { ... };
	interface A: Base { ... };
	interface B: Base { ... };
	interface AB: A, B { ... };
};

or, as a picture:

		 Example::Base
                     / \
                    /   \
                   /     \
                  /       \
	    Example::A     Example::B
                  \       /
                   \     /
                    \   /
                     \ /
		 Example::AB       

and its mapping to Java:

// Generated Java files
package myprefix.Example;
public interface Base extends CORBA.Object {
    // ... operations
}
package myprefix.Example;
public interface A 
    extends CORBA.Object, myprefix.Example.Base {
    // ... operations    
}
package myprefix.Example;
public interface B
    extends CORBA.Object, myprefix.Example.Base {
    // ... operations    
}
package myprefix.Example;
public interface AB extends CORBA.Object,
	    myprefix.Example.A,
	    myprefix.Example.B {
    // ... operations    
}

Each Java interface extends the Java interfaces for any base IDL interfaces.

Rationale

This mapping is straight forward. We have considered more complex mappings, which map the CORBA::Object (P)IDL methods to methods of the CORBA.Object Java interface. These mappings use multiple Java interfaces to correspond to one IDL interface, and impose extra runtime cost on every local method call. Our mapping makes the CORBA::Object methods a little more expensive to implement, but the general simplicity using the same interfaces for stubs and skeletons is well worth that cost.

Parameter passing modes

IDL parameter passing modes: in, out, and inout are mapped as follows:

IDL in parameters use pass-by-value. The value is not changed by the server.

IDL out parameters are mapped by passing a singleton (one element) array as a holder because the Java language has no corresponding parameter passing mode. A client supplies the singleton array of the appropriate class that is passed (by value) for each IDL out parameter. The content of the array element (but not the array itself) is modified by the invocation, and the client extracts the changed content after the invocation returns.

IDL inout parameters use the same singleton array holder as IDL out parameters do. The element is passed in by value and before the function return, the result value is assigned to the holder element. The input argument is not modified but a new value for the output argument is assigned to the array element.

Example:

/* From the IDL source: */
module Example {
	interface ResultType ... ;	
	interface InType ... ;		 
	interface OutType ... ;		 
	interface InOutType ... ;		 
	interface Modes {
		ResultType operation(in InType inArg, 
				     out OutType outArg, 
				     inout InOutType inoutArg);
	};
};
// Generated Java:
package myprefix.Example;
public interface Modes {
    myprefix.Example.ResultType operation(myprefix.Example.InType inArg,
                                 myprefix.Example.OutType[] outArg,
                                 myprefix.Example.InOutType[] inoutArg)
        throws CORBA.SystemException;
}

The result comes back as an ordinary Java result value; the in parameter needs only an ordinary value as the actual; but for the out and inout parameters, an appropriate singleton array must be constructed. A typical calling sequence for this operation might look like:


// sample Java program
myprefix.Example.Modes target = ...		// this will be the target object
myprefix.Example.InType inArg = ...		// prepare the "in" argument
myprefix.Example.OutType[] outHolder =  	// prepare to receive the "out"
	new myprefix.Example.OutType[1];
myprefix.Example.InOutType[] inoutHolder = 	// set up "in" side of "inout"
	new myprefix.Example.InOutType[1];
inoutHolder[0] = (...);
myprefix.Example.ResultType result = 		// invoke the operation
	target.operation(inArg, outHolder, inoutHolder);
... outHolder[0] ...				// use "out" value from outHolder
... inoutHolder[0] ...			  	// use "inout" value of inoutHolder

To prepare the call, the ``in`` side of the inout parameter must be put in the array for the inout actual. After the invocation, the client can use outHolder[0] to access the value of the out parameter, and inoutHolder[0] to access the out side of the inout parameter. The return result of the IDL operation is available as the result of the invocation; no holder is required.

Some designs limit the inout parameters for unbounded sequences and strings to not return longer sequences then their input. The Java mapping has NO such limitation. Such a limitation makes sense only for languages without automatic memory management.

Rationale

We have considered several designs for holder classes. One version uses holder classes named after the IDL type they are holding; the second design used holder classes named after the Java type they are holding. Using arrays bypasses the problem of how holders are named and in which package holders are stored. It also requires the smallest number of Java classes and files generated.

We have also considered to not using any holder classes for types which are represented with Java objects which are mutable. In particular for the case of inout types struct, sequence, array, and if they were mutable Any and unions, the parameter could be modified in place. We believe that our design of allocating new objects is more robust and easier to use for applications.


Attributes

IDL attributes are syntactic sugar for accessor and modifier operations for typed fields. We will define an accessor method and a modifier method, if the IDL attribute is not read-only. The name of the accessor method is the name of the attribute prefixed by ``get_''. The name of the modifier method is the name of the attribute prefixed by ``set_''.

Example

/* From the IDL source: */
module Example {
	interface SampleAttributes {
		attribute		long mutable;
		readonly attribute	long readable;
	};
};
// Generated Java:
package myprefix.Example;
public interface SampleAttributes {
    int get_mutable() throws CORBA.SystemException;
    void set_mutable(int arg) throws CORBA.SystemException;
    int get_readable() throws CORBA.SystemException;
}


Client side mapping

The Java stub class is the client-side class which provides the Java interface. It is named with the name of the IDL interface and the suffix ``_stub''. The Java stub class implements the operations defined in the Java interface analogue of the IDL interface, including inherited methods. It also implements accessor methods for the IDL attributes.

Client applications have no need to know about the stub class directly as these are instantiated by the ORB.

As the reference interface doesn't contain the methods on CORBA::Object, the stub class doesn't need to implement these methods either; see the chapter Methods on CORBA::Object. The Java stub class has a private constructor, so clients can not create new IDL object references.

A Java null can be passed anywhere a null object reference is needed.

Example

/* From the IDL source: */
module Example {
	interface ResultType ...;	 
	interface ParameterType ...;	 
	exception Barf { ... };	 
	interface Service {
		ResultType operation(in ParameterType arg) raises (Barf);
	};
};
// Generated Java:
package myprefix.Example;
public interface Service extends CORBA.Object {
    //or a subclass thereof
    myprefix.Example.ResultType operation(myprefix.Example.ParameterType arg)
        throws CORBA.SystemException, myprefix.Example.Barf;
}
// Generated Java:
package myprefix.Example;
public class Service_stub
	implements CORBA.Object, 
    	//or a subinterface thereof
    	myprefix.Example.Service { 
    //	IDL operations
    //	    Implementation of ::Example::Service::operation
    public myprefix.Example.ResultType operation(myprefix.Example.ParameterType arg)
        throws CORBA.SystemException, myprefix.Example.Barf {
    ...
}


Server side mapping

ORBs might support several methods for applications to create server objects. Support of the following method is expected:

We use the very same mapping for object references on the server side as we do on the client side.

To implement an IDL interface, an application needs to provide a class that implements the corresponding Java interface. A stubber might optionally generate a template class which could be used to fill in the actual methods. A implementer must be free to use (edit, extend) such an automatically generated template or to write the whole class from scratch.

A server side object implementation must declare itself as implementing the Java interface corresponding to the IDL interface. An ORB may impose the restriction on applications that Java servant objects must not make use of the Java finalize method. No other demands are made on an implementation. In particular, there is no requirement that the implementation extend any Java classes.

Activation of servant objects

Activation of objects can be done as described in chapter "8.2.2 Activation and Deactivations" of the CORBA 2.0 specification. We also expect ORBs to provide other means to activate objects.

Rationale

Servant classes are written by programmers. As Java classes use single inheritance, it is not appropriate for an ORB to mandate the superclass. However, a skeleton which optionally can used by a programmer comes in handy as it may contain inherited code which can be useful.

We have also considered the following requirement:

To implement an IDL interface clients also need to declare to implement the CORBA.ServantSupport Java interface. This interface does not require any methods to be implemented; it is strictly used for type checking. If an ORB vendor chooses to provide an skeleton base class for server applications, or provides the automatically generated skeleton, that skeleton base class shall be a subclass of a class named CORBA.ServantBase and shall implement CORBA.ServantSupport.

The finalize method is off limits and replaced by a specific interface to enable an ORB vendor to make circular structures containing servant objects and enforce a finalization order of its choice. This is necessary for certain ORB's to implement distributed garbage collection.

Replacement for finalize

A servant class can implement the ServantFinalizable interface to request that its servantFinalize method is called on finalization of activated servant objects. To activate this replacement finalization, the servant object uses its normal finalization method (and only this) to call CORBA.ServantFinalizer.doFinalize. All other finalization actions must be deferred to the servantFinalize method.
From the viewpoint of the application, servantFinalize is called under the same circumstances as the standard java finalize method would be called.
package CORBA;
public interface ServantFinalizable extends CORBA.Object {
    public void servantFinalize() throws Throwable; 
}

package CORBA;
public class ServantFinalizer {
    public static void doFinalize(ServantFinalizable obj) {
    //... ensures call of obj.servantFinalize() 
    } 
}

Rationale
Providing a replacement mechanism for finalization has been considered because some applications did not want to give up on their own finalization.

The requirement on the server application to call ServantFinalizer.servantFinalize in its normal finalize method enables an ORB which doesn't have any internal reasons to call servantFinalize to do so easily without keeping any state variables.

While the mechanism of calling ServantFinalizer.doFinalize initially looks complicated, it bears no runtime cost if the application does not require its own finalization.


Methods on CORBA::Object

The CORBA::Object type maps to the Java interface CORBA.Object. The Java interface for each user-defined IDL interface extends the Java interface CORBA.Object, or a subclass thereof, so that any Java interface can be passed anywhere a CORBA.Object is expected.
The CORBA.Object interface does not include Java methods that manipulate CORBA::Object object references but a class CORBA.ObjectClass provides static methods for this purpose.

package CORBA;
public class ObjectClass
    extends ...
    implements ... {
    //
    //	    Check if this object supports the interface represented 
    //	    by the argument.
    public static boolean isA(CORBA.Object that, String repositoryIdentifier) 
	    throws CORBA.SystemException { ... }
	    //Optionally may accept a superinterface of CORBA.Object 
    
    // Other methods as specified in section 7.2 of the CORBA 2 spec
}
Applications must not subclass CORBA.Object directly because ORBs are allowed to return implementation specific subinterfaces of CORBA.Object and might relax input arguments to a implementation specific superinterfaces of CORBA.Object.

Since Java has automatic memory management, duplicate and release are not required functions.

Rationale

Relying on garbage collection for duplicate and release is obvious and sufficient for most applications. It might make sense however in certain circumstances to have application specific duplicate and release functions. We do not include this in the standard because the standard does not preclude a vendor from introducing duplicate and release functionality to be used with particular objects or classes specified to require that functionality.

The methods of CORBA::Object appear in CORBA.ObjectClass instead of CORBA.Object so that server programmers don't have to implement any generic CORBA-mandated methods.


Any and TypeCode

TypeCode

The IDL pseudo-object type TypeCode maps to the Java class CORBA.TypeCode. Instances of CORBA.TypeCode are generated in an implementation-specific manner. Instances of CORBA.TypeCode for each type described in an IDL file should be available to the programmer after the package initialization for the packages produced for that file is finished. A static method ``find'' is provided to allow the programmer to obtain the TypeCode corresponding to a given repository ID.

package CORBA;
public class TypeCode extends ... {
    public static TypeCode find(java.lang.String corba_rep_id)
        throws CORBA.SystemException {...}
    public java.lang.String id()
	throws CORBA.SystemException {...}
    public java.lang.String name()
	throws CORBA.SystemException {...}
    public int kind()
	throws CORBA.SystemException {...}
    // ... Other methods as specified in section 6.7 of the CORBA 2 spec ...
     
    public static final TypeCode tc_null;
    public static final TypeCode tc_void;
    public static final TypeCode tc_short;
    public static final TypeCode tc_long;
    public static final TypeCode tc_ushort;
    public static final TypeCode tc_ulong;
    public static final TypeCode tc_float;
    public static final TypeCode tc_double;
    public static final TypeCode tc_boolean;
    public static final TypeCode tc_char;
    public static final TypeCode tc_octet;
    public static final TypeCode tc_any;
    public static final TypeCode tc_TypeCode;
    public static final TypeCode tc_Object;
    public static final TypeCode tc_string;
}
TypeCodes are constant.

Type kinds

The TCKind class defines integer values which describe type kinds.
package CORBA;
public class TCKind { 
    public static final int tk_null = 0;
    public static final int tk_void = 1;
    public static final int tk_short = 2;
    public static final int tk_long = 3;
    public static final int tk_ushort = 4;
    public static final int tk_ulong = 5;
    public static final int tk_float = 6;
    public static final int tk_double = 7;
    public static final int tk_boolean = 8;
    public static final int tk_char = 9;
    public static final int tk_octet = 10;
    public static final int tk_any = 11;
    public static final int tk_TypeCode = 12;
    public static final int tk_objref = 14;
    public static final int tk_struct = 15;
    public static final int tk_union = 16;
    public static final int tk_enum = 17;
    public static final int tk_string = 18;
    public static final int tk_sequence = 19;
    public static final int tk_array = 20;
    public static final int tk_alias = 21;
    public static final int tk_except = 22; 
    // the actual numeric values are implementation dependent,
    // and implementation-dependent extension typekinds may be present.
    
    public static final int narrow(int i) 
        throws CORBA.EnumerationRangeException /* or a subclass */ {...}
}

Rationale

We are leaving the C-style naming tc and tk prefixes to avoid conflicts with Java keywords.

Any

The IDL type Any maps to the Java class CORBA.Any.

The Any class has no public constructor; there is a static ``alloc'' method which allocates and initializes the Any. The Any class also has ``type'' and ``value'' methods for obtaining the TypeCode of the Any, and its value as a Java object.

All ORB methods which accept an Any may accept a superclass; all methods which generate an Any may generate a subclass. As a consequence of the class not being fully specified, portable applications can not subclass Any directly.

package CORBA:
public class Any extends ... {
    public static Any alloc(CORBA.TypeCode type, java.lang.Object value) 
        throws CORBA.SystemException {
        // The Any return value can be a subclass.
        // The formal value input argument needs to have the Java class
        // or subclass for the mapping of the IDL type.  If an input  
        // argument is mapped to a Java basic type, this procedure will 
        // accept the corresponding Java wrapper class.
        ... }
    public TypeCode type() throws CORBA.SystemException {
        // Returns a TypeCode for the value contained in the Any.
        ...
        }
    public java.lang.Object value() throws CORBA.SystemException {
        // Returns a Java value for the value contained in the Any.
        // Returns instances of  Java wrapper classes instead of Java basic types.
        ...
        }
    //... More methods are desribed in the section on helper classes
}
All operations may throw a CORBA.SystemException or a subclass thereof; in particular CORBA.DiscriminantException may be thrown.

Rationale

We have considered an alternate design where IDL Any would be represented with a java.lang.Object. For discrimination among variants the Java type system would be used. However, because multiple IDL types may be mapped to one Java type, this design provides inadequate discrimination.

We are using a static method to create Any to allow ORBs to deal in subclasses.

We were contemplating a design where Any values were mutable. This design used a set method to assign some value to an Any and a setClone method to extract and assign the value from another Any. Modifying an CORBA.Any would not have been an atomic operation; synchronization or single threaded usage were the client's responsibility. We decided that the simplicity of the immutable design is desirable. If ever an application would require mutability it can use a holder array; respectively in IDL make an interface with an Any attribute.

Helper classes

User defined named IDL types have a helper Java class associated which is named after the type with the suffix ``_help''. The helper class provides static methods to manipulate types. These include operations to construct an Any value, getting the type or the value contained by an Any, getting the repository id for the type, and getting the typecode for the type.

For the IDL type, barType, the following helper class is generated.

// Generated Java:
// Assuming barType is an IDL type defined in module Example
// and mappedBarType is the Java type prescribed by the 
// mapping of barType.
//
package myprefix.Example; 
public class barType_help {
    public static CORBA.Any toAny(mappedBarType t) 
        throws CORBA.SystemException {...}
    public static mappedBarType fromAny(CORBA.Any) 
        throws CORBA.SystemException {...}
    public static boolean isContained(CORBA.Any)
        throws CORBA.SystemException {...}
    public static CORBA.TypeCode typecode()
        throws CORBA.SystemException {...}
    public static String repository_id()
        throws CORBA.SystemException {...}
} 
The issue of a helper class for anonymous IDL sequences or arrays (i.e., not named with a typedef) is not addressed.

For IDL standard types we intend to include methods to the Any class as follows, where Foo stands for the IDL types short, long, ushort, ulong, float, double, boolean, char, octet, any, TypeCode, Object, string and mappedFoo stands for the Java type from the mapping of Foo:

// In CORBA.Any:
//
public static Any from_Foo(mappedFoo value) 
        throws CORBA.SystemException {...}
public boolean contains_Foo() 
        throws CORBA.SystemException {...}
public mappedFoo value to_Foo(Any) 
        throws CORBA.SystemException {...}


References

``The Common Object Request Broker: Architecture and Specification'', Revision 2.0, July 1995)
    http://www.omg.org/corba2/corb2prf.htm 

The Java Language Specification
    http://www.javasoft.com/doc/language_specification/index.html 

Mapping proposal from Sun
    http://splash.javasoft.com/pages/IDLtoJava.html 

Mapping proposal from Blackwidow
    http://www.visigenic.com/BW/idl2javamapping.html

Mapping proposal from Orbix
    http://www.iona.com/Orbix/OrbixWeb/doc/pguide/map.html



Changes compared to the submission from Dec 20

This printed copy is not exactly the document provided for submission. We made a few editorial changes, fixed two bugs in Java examples and also the following changes:

The final Java modifier for the mapping of structs is removed.
Standard exceptions are created with one single call; Standard exceptions which are not IDL defined are subclases of CORBA.BAD_PARAM.
A restriction on ObjectClass is removed.
Included a new paragraph on a replacement for the finalize Java method.
Introduction of helper classes to support TypeCode and Any.

Change-bar like comments can be found in the html source of this document.


Copyright (c) 1996, 1997 Xerox Corporation. All Rights Reserved.

The companies and organizations listed above hereby grant a royalty-free license to the Object Management Group (OMG) for world-wide distribution of this document or any derivative works thereof, so long as the OMG reproduces the copyright notices and the below paragraphs on all distributed copies.

The material in this document is provided for evaluation by the OMG. Submission of this document does not represent a commitment to implement any portion of this specification in the products of the above said companies and organisations.

While the information in the publication is believed to be accurate, the companies and organisations listed above make no warranty of any kind with regard to this material including but not limited to the implied warranties of merchantability and fitness for a particular purpose. The companies and organisations listed above shall not be liable for errors contained herein or for incidental or consequent damages in connection with the furnishing, performance or use of this material. The information contained in this document is subject to change without notice.

This document contains information which is protected by copyright. All Rights Reserved. No part of this work covered by copyright here on may be reproduced or used in any form or by any means - graphic, electronic, or mechanical, including photocopying, recording, taping, or information storage and retrieval systems - without permission of the copyright owners. All copies of this document must include the copyright and other information contained on this page.

The copyright owners grant the Object Management Group permission to reproduce and use the information contained in this document. The copyright owners grant a limited waiver of the copyright on this document to members of the Object Management Group so that they can each reproduce up to 50 copies of this document for their internal use as part of the OMG evaluation process.

RIGHTS RESERVED LEGEND. Use, duplication, or disclosure by government is subject to restrictions as set forth in subdivision (c)(1)(ii) of the Right in Technical Data and Computer Software Clause at DFARS 252.227.7013.

CORBA, OMG IDL are trademarks of The Object Management Group, Inc.
Java is a trademark of Sun Microsystems Inc.