Issue 1980: Updated proposal for the OBV Java mapping (java-rtf) Source: (, ) Nature: Revision Severity: Summary: Summary: updated proposal for the OBV Java mapping which addresses a number of issues which have been raised by us and others. This proposal is based on a number of discussions and previous proposals and current OMG submissions (thanks to Simon Nash and Bernard Normier). As with previous poposals, these are not currently formal proposals, just working drafts. ;-) Here are the current issues: 1. Java valuetypes cannot unmarshal recursive references to themselves. This is the same problem that occurs with custom valuetypes. 2. The current language mapping mixes both generated code with user written code in the same source file. This poses a very complex "tool" issue for IDL compilers which is unnecessarily complex. 3. Java valuetypes need a way to unmarshal the state of their base class. 4. The addition of the new Helper interface adds ~400 bytes to every Helper class, of which there are about 250 in a typical ORB implementation. Which is an overhead of about 100k just to support an optimization of a corner case in RMI/IIOP where an RMI type happens to contain an IDL type. This doesn"t even begin to address the bloat that would occur to user code as well as any additional CORBA services. The space/time tradeoff here appears to have gone the wrong way. 5. The ValueHelper interface contains the method get_safe_base_ids, which is inconsistent with current OBV terminology. 6. The marshaling of boxed types should be considered carefully, because of the special casing required for boxed strings, arrays, and sequences. 7. The compiler should provide compile time enforcement of init() declarations. Resolution: resolved, see revised text Revised Text: The solution is modify the mapping so as to use an easier deal with form of a 2 class mapping, much like C++, to add facilites that will fix the bugs that don't allow recursive structures to be marshaled and unmarshaled, reduce the "bloat", handle all the boxed values correctly, etc. This proposal, coupled with the proposal to fix Issue 1981, which deals with the "init" portion of the issue at the IDL level, fixes all the known problems with the OBV/Java mapping. Revised Text: The changes are relative to version of Chapter 25 which has had Issue 1897 Evolving the org.omg.* APIs applied to it (available as ftp://ftp.omg.org/orbrev/drafts/idljava_2_4v1.2.pdf ) Add in section 25.4.1.4 after ObjectHolder final public class ValueBaseHolder { public org.omg.CORBA.portable.ValueBase value; public ValueBaseHolder() {} public ValueBaseHolder(org.omg.CORBA.portable.ValueBase initial) {...} public void _read(org.omg.CORBA.portable.InputStream is) {...} public void _write(org.omg.CORBA.portable.OutputStream os){...} public org.omg.CORBA.TypeCode _type(){...} } Replace section 25.5.1 with: 25.5.1 Generic BoxedValueHelper Interface package org.omg.CORBA.portable; public interface BoxedValueHelper { java.io.Serializable read_value(InputStream is); void write_value(OutputStream os, java.io.Serializable value); java.lang.String get_id(); } In 25.5.2 delete the 2nd and 5th paragraphs. In 25.5.2 delete the specification of the "generated Java helper (value types) In 25.5.2, in the specification of the "generated Java helper (non value types): a. delete the "(non value types)" from the comment b. Add the following methods to the end of the generated <typename>Helper class specification: // for each initializer in non abstract value type (see section 25.5.2.1) public static <typename> <initializername> (org.omg.CORBA.ORB orb, [<initializer arguments>]) {...} c. Remove the paragraph following that starts with: "For any user defined, value type ... " Add a new section 25.5.2.1 "Value type initializer convenience functions" as follows: For each initializer in a value type declaration, a corresponding static convenience method is generated in the helper class for the value type. The name of this method is the name of the initializer. This method takes an orb instance and all the arguments specified in the initializer argument list. The implementation of each of these methods will locate a <typename>ValueFactory (see section xxx) and call the identically named method on the ValueFactory passing in the supplied arguments. Replace all of section 25.13 Mapping for Value Type with: 25.13.1 Supporting interfaces for value types 25.13.1.1 ValueBase interface package org.omg.CORBA.portable; public interface ValueBase extends IDLEntity { String[] _truncatable_ids(); } All values implement ValueBase either directly (for boxed primitives - see section 25.14.1), or indirectly by implementing either the StreamableValue or CustomValue interface (see below). 25.13.1.2 StreamableValue interface package org.omg.CORBA.portable; public interface StreamableValue extends Streamable, ValueBase { } All non-boxed IDL valuetypes that are not custom marshalled, implement this interface. 25.13.1.3 CustomMarshal interface package org.omg.CORBA; public interface CustomMarshal { public void marshal (org.omg.CORBA.DataOutputStream os); public void unmarshal (org.omg.CORBA.DataInputStream is); } Implementors of custom marshalled values implement the above interface to provide custom marshalling. 25.13.1.4 CustomValue interface package org.omg.CORBA.portable; public interface CustomValue extends ValueBase, org.omg.CORBA.CustomMarshal { } All custom value types generated from IDL implement this interface. 25.13.1.5 ValueFactory interface package org.omg.CORBA.portable; public interface ValueFactory { java.io.Serializable read_value(InputStream is); } The ValueFactory interface is the native mapping for the IDL type CORBA::ValueFactory. The ValueFactory's read_value() method is called by the ORB runtime in the process of unmarshaling a valuetype. A user must implement this method as part of implementing a type specific ValueFactory. In this implementation, the user must call java.io.Serializable is.read_value(java.io.Serializable) with a blank valuetype to use for unmarshalling. The value returned by the stream is the same value passed in with all the data unmarshalled. 25.13.2 Basics for stateful value types A concrete value type (i.e. one that is not declared as abstract) is mapped to an abstract Java class with the same name, and a factory Java interface with the suffix "ValueFactory" appended to the value type name. In addition, a helper class with the suffix "Helper" appended to the value type name and a holder class with the suffix "Holder" appended to the value type name shall be generated. The specification of the generated holder class is as follows: public final class <typename>Holder implements org.omg.CORBA.portable.Streamable { public <typename> value; public <typename>Holder () {} public <typename>Holder (final <typename> initial) { value = initial; } public void _read (final org.omg.CORBA.portable.InputStream input) {...} public void _write (final org.omg.CORBA.portable.OutputStream output) {...} public org.omg.CORBA.TypeCode _type () {...} } The value type's mapped Java abstract class contains instance variables that correspond to the fields in the state definition in the IDL declaration. The order and name of the Java instance variables shall be the same as the correspondng IDL state fields. Fields that are identified as public in the IDL are mapped to public instance variables. Fields that are identified as private in the IDL are mapped to protected instance variables in the mapped Java class. The Java class for the value type extends either org.omg.CORBA.portable.CustomValue or org.omg.CORBA.portable.StreamableValue, depending on whether it is declared as custom in IDL or not, respectively. The generated Java class shall provide implementation of the ValueBase interface for this value type. The value type's generated value factory interface extends org.omg.CORBA.portable.ValueFactory and contains one method corresponding to each initializer declared in the IDL. The name of the method is the same as the name of the initializer, and the initializer arguments are mapped in the same way as in parameters are for IDL operations. The implementor shall provide a factory class with implementations for the methods in the generated value factory interface. When no initializers are declared in IDL, then the value type's value factory is eliminated from the mapping and the implementor shall simply implement org.omg.CORBA.portable.ValueFactory to provide the method body for read_value(). The inheritance scheme and specifics of the mapped class depend upon the inheritance and implementation characteristics of the value type and are described in the following subsections. The mapped Java class contains abstract method definitions which correspond to the operations and attributes defined on the value type in IDL. An implementor of the value type extends the generated Java class to provide implementation for the operations and attributes declared in the IDL, including those for any derived or supported value types or interfaces. 25.13.2.1 Inheritance from values - Value types that do not inherit from other values or interfaces: For non custom values, the generated Java class also implements the StreamableValue interface and provides appropriate implementation to marshal the state of the object. For custom values, the generated class extends CustomValue but does not provide an implementation for the CustomMarshal methods. - inheritance from other stateful values The generated Java class extends the Java class to which the inherited value type is mapped - inheritance from abstract values The generated Java class implements the Java interface to which the inherited abstract value is mapped(see section 25.13.3). - supported interfaces The Java class implements the Operations Java interface of all the interfaces(if any) that it supports. (Note that the operations interface for abstract interfaces does not have the "Operations" suffix, see section 25.12.1.1). The implementation of the supported interfaces of the value type shall use the tie mechanism, to tie to the value type implementation. 25.13.3 Abstract Value Types An abstract value type maps to a Java interface that implements ValueBase and contains all the operations and attributes specified in the IDL, mapped using the normal rules for mapping operations and atttributes. Abstract value types cannot be implemented directly. They must only be inherited by other stateful value types or abstract value types. 25.13.4 CORBA::ValueBase CORBA::ValueBase is mapped to java.io.Serializable. The get_value_def() operation is not mapped to any of the classes associated with a value type in Java. Instead it appears as an operation on the ORB pseudo object in Java(see "public static org.omg.CORBA.Object get_value_def(String repId)" in section 25.19.10). Note: This implies fixing up the referenced text in !too 25.19.10 to have the correct signature 25.13.5 Examples In 25.13. 4 Example A In the IDL change init(in long w); to: factory create(in long w); Replace the generated Java by: // generated Java package ExampleA; public abstract class WeightedBinaryTree implements org.omg.CORBA.portable.StreamableValue { // instance variables protected int weight; protected ExampleA.WeightedBinaryTree left; protected ExampleA.WeightedBinaryTree right; abstract public int[] preOrder (); abstract public int[] postOrder (); public org.omg.CORBA.TypeCode _type () {...} public void _read (final org.omg.CORBA.portable.InputStream _input) { // read state information using the wire format ... } public void _write (final org.omg.CORBA.portable.OutputStream _output) { .... } public java.lang.String[] _truncatable_ids () {...} } public final class WeightedBinaryTreeHelper { < ed note: put all the helper methods here> public static WeightedBinaryTree create(ORB orb, int w) { ... } } final public class WeightedBinaryTreeHolder implements org.omg.CORBA.portable.Streamable { ... <Note: the code for this isn't changing so just leave the old code there> } public interface WeightedBinaryTreeValueFactory extends org.omg.CORBA.portable.ValueFactory { public ExampleA.WeightedBinaryTree create (int w); } In 25.13.5 Example B Keep the IDL and the Java mapping of the Printer interface as is. Replace the generated Java for the WeightedBinaryTree with the following: // generated java package ExampleB; public abstract class WeightedBinaryTree implements org.omg.CORBA.portable.StreamableValue, PrinterOperations { protected int weight; protected ExampleB.WeightedBinaryTree left; protected ExampleB.WeightedBinaryTree right; abstract public int[] preOrder (); abstract public int[] postOrder (); public org.omg.CORBA.TypeCode _type () { ... } public void _read (final org.omg.CORBA.portable.InputStream _input) { ... } public void _write (final org.omg.CORBA.portable.OutputStream _output) { ... } public java.lang.String[] _truncatable_ids () { ... } } public final class WeightedBinaryTreeHelper { .... // helper methods... < ed note: put all the helper methods here> } public final class WeightedBinaryTreeHolder { ... <note this hasn't changed, fill in old one here> } // user written code for default ValueFactory public class WeightedBinaryTreeDefaultFactory implements org.omg.CORBA.portable.ValueFactory { public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream is) { //user implements code } } Add a new 25.13.5 Example C // IDL typedef sequence<unsigned long> WeightedSeq; module ExampleC { custom valuetype WeightedBinaryTree { private unsigned long weight; private WeightedBinaryTree left; private WeightedBinaryTree right; factory create(in long w); WeightedSeq preOrder(); WeightedSeq postOrder(); }; }; // generated Java package ExampleC; abstract public class WeightedBinaryTree implements org.omg.CORBA.portable.CustomValue {...} public final class WeightedBinaryTreeHelper {...} public final class WeightedBinaryTreeHolder {...} [ editing note: fill in the ... as an aid to the reader ] 25.13.6 Keep as is currently in the specification 25.13.7 ValueFactory and Marshaling Replace second bullet in factory lookup algorithm by: - If this is not successful and the repository id is a standard IDL repository id that starts with "IDL:",then extract the class name from the repository id by stripping of the "IDL:" header and ":<major>.<minor>" version information trailer and replacing all "/"s with "."s. Then attempt to load a value factory by appending a "DefaultFactory" suffix to the above class name. Replace third bullet in factory lookup algorithm by: - If this is not successful and the repository id is a standard RMI repository id that begins with "RMI:", then extract the class name from the repository id by stripping of the "RMI:" header and the ":<hashcode>:[<suid>]" trailer and applying all necessary conversions(see section 26.****). The ValueHandler interface is used to read in the value, if it does not implement IDL Entity. Replace paragraph following the bullets by: The IDL native type ValueFactory is mapped in Java to org.omg.CORBA.portable.ValueFactory. In 25.14 Mapping for Value Box Type, replace the 3rd paragraph with the following: A boxed value needs to be treated differently than regular values in Java. Boxed values don't have factories and don't implmenent either the StreamableValue or CustomValue interfaces, so their marshalling and unmarshalling is performed by a boxed value helper object. In all cases, code can be generated to unmarshal the boxed type. No user code is required for boxed values. The BoxedValueHelper interface is implemented by all generated Helper classes for boxed valuetypes. The inherited read_value() method is called by the ORB runtime in the process of unmarshalling a boxed valuetype. This is required for types that are immutable either in content (eg, string), or size (eg, sequences). The write_value() method call is used for marshalling the value box. There are two general cases to consider. value boxes of primitive Java types and value boxes for entities that are mapped to java classes. In Section 25.14.1 Replace the first Java class <box_name> to be: public class <box_name> implements ValueBase { public <mapped_primitive_Java_type> value; public <box_name>(<mapped_primitive_Java_type> initial) { value = initial; } private static String[] _ids = { <box_name>Helper.id() }; public String[] _truncatable_ids() { return _ids; } } Replace the third Java class <box_name>Helper to be: final public class <box_name>Helper implements org.omg.CORBA.portable.BoxedValueHelper { public <box_name> read_value(InputStream is) {...} public write_value(OutputStream is, <box_name> value) {....} public String get_id() { ... } .... // other helper methods } In Section 25.14.1.1 Primitive Type example: Replace the MyLong class by: public class MyLong implements ValueBase { public int value; public MyLong(int initial) { value = initial; } private static String[] _ids = { MyLongHelper.id() }; public String[] _truncatable_ids() { return _ids; } } Replace MyLongHelper by: final public class MyLongHelper implements org.omg.CORBA.portable.BoxedValueHelper { public MyLong read_value(InputStream is) {...} public write_value(OutputStream is, MyLong value) {....} public String get_id() { ... } .... // other helper methods } Add to end of paragraph on 25.14.2 //IDL valuetype <box_name> <IDLtype>; final public class <box_name>Helper implements org.omg.CORBA.portable.BoxedValueHelper { public <IDLType> read_value(InputStream is) {...} public write_value(OutputStream is, <IDLType> value) {....} .... // other helper methods } final public class <box_name>Holder implements org.omg.CORBA.portable.Streamable { public <mapped_java_class> value; ... } Add a new section 25.14.3 Examples // IDL module A { valuetype BoxedString string; }; // generated Java package A; public final class BoxedStringHelper implements org.omg.CORBA.portable.BoxedValueHelper { private static final BoxedStringHelper _instance = new BoxedStringHelper(); public static java.lang.String read (final org.omg.CORBA.portable.InputStream _input) { if (!(_input instanceof org.omg.CORBA_2_3.portable.InputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } return (java.lang.String)((org.omg.CORBA_2_3.portable.InputStream)_input).read_value(_instance); } public static void write (final org.omg.CORBA.portable.OutputStream _output, final java.lang.String value) { if (!(_output instanceof org.omg.CORBA_2_3.portable.OutputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } ((org.omg.CORBA_2_3.portable.OutputStream)_output).write_value(value, _instance); } public static void insert (org.omg.CORBA.Any any, java.lang.String value) {...} public static java.lang.String extract (org.omg.CORBA.Any any) {...} public static org.omg.CORBA.TypeCode type () {...} public static java.lang.String id () {...} public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream _input) { java.lang.String result; result = _input.read_string(); return (java.io.Serializable)result; } public void write_value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable value) { if (!(value instanceof java.lang.String)) { throw new org.omg.CORBA.MARSHAL(); } java.lang.String valueType = (java.lang.String)value; _output.write_string(valueType); } public java.lang.String get_id () { return id(); } } public final class BoxedStringHolder implements org.omg.CORBA.portable.Streamable {....} Section 25.14.3.1 Example B // IDL struct idlStruct { short x; }; module A { valuetype BoxedStruct idlStruct; }; // generated Java package A; public final class BoxedStructHelper implements org.omg.CORBA.portable.BoxedValueHelper { private static final BoxedStructHelper _instance = new BoxedStructHelper(); public static idlStruct read (final org.omg.CORBA.portable.InputStream _input) { if (!(_input instanceof org.omg.CORBA_2_3.portable.InputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } return (idlStruct)((org.omg.CORBA_2_3.portable.InputStream)_input).read_value(_instance); } public static void write (final org.omg.CORBA.portable.OutputStream _output, final idlStruct value) { if (!(_output instanceof org.omg.CORBA_2_3.portable.OutputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } ((org.omg.CORBA_2_3.portable.OutputStream)_output).write_value(value, _instance); } public static void insert (final org.omg.CORBA.Any any, final idlStruct value) {...} public static idlStruct extract (final org.omg.CORBA.Any any) {...} public static org.omg.CORBA.TypeCode type () {...} public static java.lang.String id () {...} public java.io.Serializable read_value (final org.omg.CORBA.portable.InputStream _input) { final idlStruct result; result = idlStructHelper.read(_input); return (java.io.Serializable)result; } public void write_value (final org.omg.CORBA.portable.OutputStream _output, final java.io.Serializable value) { if (!(value instanceof idlStruct)) { throw new org.omg.CORBA.MARSHAL(); } idlStruct valueType = (idlStruct)value; idlStructHelper.write(_output, valueType); } public java.lang.String get_id () { return id(); } } public final class BoxedStructHolder implements org.omg.CORBA.portable.Streamable { .... } In Section 25.19.10 ORB in the definition of the org.omg.CORBA_2_3.ORB class: Change the signature of register_value_factory to: public org.omg.CORBA.portable.ValueFactory register_value_factory(String id, org.omg.CORBA.portable.ValueFactory factory); Change the return type lookup_value_factory() from: org.omg.CORBA.portable.ValueHelper to: org.omg.CORBA.portable.ValueFactory In Section 25.21.4 In the definition of the org.omg.CORBA_2_3.portable.InputStream: Change both declarations of read_Value to read_value In the 2nd overloaded read_Value change the parameter type from: ValueHelper helper to: java.lang.String rep_id Change both declarations of read_Abstract to read_abstract_interface Add the following new methods: public java.io.Serializable read_value(org.omg.CORBA.portable.BoxedValueHelper factory) { throw new org.omg.CORBA.NO_IMPLEMENT(); } public java.io.Serializable read_value(java.io.Serializable) { throw new org.omg.CORBA.NO_IMPLEMENT(); } In the definition of the org.omg.CORBA_2_3.portable.OutputStream: Change both declarations of write_Value to write_value In the 2nd overloaded write_Value change the 2nd parameter type from: ValueHelper value to: java.lang.String rep_id Change the declaration of write_Abstract to write_abstract_interface Delete the start_block and end_block methods Add the following new method: public void write_value(java.io.Serializable value, org.omg.CORBA.portable.BoxedValueHelper factory) { throw new org.omg.CORBA.NO_IMPLEMENT(); } Actions taken: September 18, 1998: received issue February 26, 1999: moved from obv_rtf to java rtf June 4, 1999: closed issue Discussion: End of Annotations:===== Return-Path: Sender: "George Scott" Date: Fri, 18 Sep 1998 18:06:10 -0700 From: "George M. Scott" Organization: Inprise Corporation To: obv-rtf@omg.org, java-rtf@omg.org Subject: Yet another OBV/Java language mapping proposal Below is an updated proposal for the OBV Java mapping which addresses a number of issues which have been raised by us and others. This proposal is based on a number of discussions and previous proposals and current OMG submissions (thanks to Simon Nash and Bernard Normier). As with previous poposals, these are not currently formal proposals, just working drafts. ;-) Here are the current issues: 1. Java valuetypes cannot unmarshal recursive references to themselves. This is the same problem that occurs with custom valuetypes. 2. The current language mapping mixes both generated code with user written code in the same source file. This poses a very complex "tool" issue for IDL compilers which is unnecessarily complex. 3. Java valuetypes need a way to unmarshal the state of their base class. 4. The addition of the new Helper interface adds ~400 bytes to every Helper class, of which there are about 250 in a typical ORB implementation. Which is an overhead of about 100k just to support an optimization of a corner case in RMI/IIOP where an RMI type happens to contain an IDL type. This doesn't even begin to address the bloat that would occur to user code as well as any additional CORBA services. The space/time tradeoff here appears to have gone the wrong way. 5. The ValueHelper interface contains the method get_safe_base_ids, which is inconsistent with current OBV terminology. 6. The marshaling of boxed types should be considered carefully, because of the special casing required for boxed strings, arrays, and sequences. 7. The compiler should provide compile time enforcement of init() declarations. Here is our complete proposal: The org.omg.CORBA.portable.Helper and org.omg.CORBA.portable.ValueHelper interfaces are removed from the mapping. Instead the following set of interfaces takes their place: package org.omg.CORBA.portable; public interface StreamableValue extends Streamable, IDLEntity { String[] _truncatable_ids(); } public interface ValueFactory {} public interface BoxedValueFactory extends ValueFactory { java.io.Serializable create_for_unmarshal(InputStream is); void read_Value(InputStream is, java.io.Serializable value); } public interface StandardValueFactory extends ValueFactory { java.io.Serializable create_for_unmarshal(); } The StremableValue interface is used to perform marshalling of values. All non-boxed valuetypes generated from IDL implement this interface. Boxed valuetypes must be treated specially. The ValueFactory interface is simply a marker, and is the native mapping for the IDL type CORBA::ValueFactory. The StandardValueFactory's create_for_unmarshal method is called by the ORB runtime in the process of unmarshaling a valuetype. A user must implement this method as part of implementing a type specific ValueFactory. The BoxedValueFactory's create_for_unmarshal method is also called by the ORB runtime in the process of unmarshalling a valuetype. However, unlike the unboxed variant, this method takes an InputStream so that some unmarshalling can occur before returning the value. This is required, for example to unmarshal boxed sequences and strings. The read_Value call is then called to complete unmarshalling (in some cases this call may be a no-op). An IDL valuetype is now mapped to two Java classes, a value class and a Factory class. The value class implements the StreamableValue interface, whereas the factory class implements either the StandardValueFactory or BoxedValueFactory interfaces. The Helper class generated for values is the same as that for any other IDL constructed type (e.g. structs, unions, etc.). For example: // IDL valuetype A { public long l; private short s; void foo(); init(long l); }; would now map to the following abstract class: abstract public class A implements org.omg.CORBA.portable.StreamableValue { public int l; protected short s; abstract public void foo(); public void _read(org.omg.CORBA.portable.InputStream is) { l = is.read_long(); s = is.read_short(); } public void _write(org.omg.CORBA.portable.OutputStream os) { os.write_long(l); os.write_short(s); } public void _type() { return AHelper.type(); } private String[] _ids = { AHelper.id(); }; public String[] _truncatable_ids() { return _truncatable_ids; } } And the Factory class: abstract public AValueFactory implements org.omg.CORBA.portable.StandardValueFactory { // convenience functions (proper exception handling not shown) public AValueFactory getFactory(org.omg.CORBA.ORB) { org.omg.CORBA.portable.ValueFactory factory = orb.lookup_value_factory(AHelper.id()); return (AValueFactory) factory; } public static A create(org.omg.CORBA.ORB orb, int l) { return getFactory(orb).init(l); } // abstract methods abstract public A init(int l); } Each generated factory class contains an abstract init() method for each init() declared in IDL. Or if no inits were specified in IDL, it contains an abstract init() method which takes no arguments. There is a static getFactory() method generated which takes an ORB as an argument, and is simply a convenience function for calling ORB.lookup_value_factory(), but provides type safety. There is also a static create() method generated for each init() method which is also a convenience function for calling the init() funtions in a simple fashion. For example to create an instance of valuetype A in the above example one would do the following: A a = AValueFactory.create(orb, 35); This method would return an instance of A, using the currently registered factory for the A valuetype. The user must provide concrete implementations of both the value and the value factory. By convention the name of the factory should be the name of the value appeneded by DefaultFactory for the ORB to be able to find a default factory automatically. For example the following is a valid implementation of A: class AImpl extends A { A(int l) { ... } A() { ... } public void foo() { ... } } class ADefaultFactory extends AValueFactory { public java.io.Serializable create_for_unmarshal() { return new A(); } public A init(int l) { return new A(l); } } A boxed value is treated specially, due to the mapping of boxed values to Java. For example: valuetype BoxedString string; Generally, the type being boxed will not be a valuetype, so special processing is required, epsecially for boxed strings, arrays, and sequences. The above example will map to java.lang.String, and the compiler will automatically generate a default factory for boxed values (the user does not write the factory for boxed values, in fact no user code is required for any boxed values): public class BoxedStringDefaultFactory { public java.io.Serializable create_for_unmarshal(org.omg.CORBA.portable.InputStream is) { return is.read_string(); } public void read_Value(org.omg.CORBA.portable.InputStream is, java.io.Serializable value) { // do nothing for this case. } } The following methods are added to InputStream and OutputStream: public class OutputStream { public void write_Value(java.io.Serializable value, String repository_id); } public class InputStream { public java.io.Serializable read_Value(String repository_id); } These methods replace the calls which preivously took the ValueHelper. The repository_id specified is always the respository_id of the formal type. Our proposal addressed our seven issues: 1. Java values can now correctly support recursive marshalling of themselves. This is supported through the create_for_unmarshal method which allows the ORB to create an instance of the value before unmarshalling allowing the ORB to do all necessary bookkeeping. 2. Generated code is now separated from user code. All generated code for a value is now isolated in an abstract base class which has a ValueBase extension. 3. Since the marshalling code is now on the values themselves, base class marshalling may now be accomplished using super._read() and super._write(). 4. The Helper interface has been removed to reduce the overall space requirement for the mapping. 5. get_safe_base_ids has been renamed _truncatable_ids and is now on a different interface. 6. Boxed value are treated specially, by defining a special valuefactory interface for boxed values. 7. inits are now enforced through the compiler. George Return-Path: Date: Mon, 21 Sep 1998 14:12:10 +0100 From: Simon Nash Organization: IBM To: "George M. Scott" CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Yet another OBV/Java language mapping proposal References: <36030382.B253EA3A@inprise.com> George, As you can imagine, I have a lot of comments on this. I'll start with minor corrections to your proposal. 1. Your example shows class A having a method _ids() that is declared as returning an array of Strings. However, it returns the result of AHelper.id(), which is a String. There is no explanation of how this method is used. As far as I can tell, this method should be called _id and return a single String. 2. In your example code, the getFactory method should be declared as static, and its parameter name "orb" is missing. 3. Both "new" operators in ADefaultFactory should be for AImpl, not A. Next, aspects of this proposal that need clarification: 4. The purpose of the read_Value method on BoxedValueFactory is not clear. What is the situation for which the create_for_unmarshal method cannot complete unmarshalling? Problems with this proposal: 5. It requires reflective calls when marshalling boxed values for non-primitive types. This is because the Java classes generated for these boxed values do not implement the StreamableValue interface with its _write method. With the current spec, this is not a problem because the ORB's marshalling code can always call the value helper instance's write_Value method. 6. Too many classes are generated. The current spec requires Holder, Helper, and implementation classes only. I would be willing to add one more class (the abstract base class) to solve the tool issue of mixing generated code with user code, and the ability to provide different implementations. However, this proposal adds a further 2 classes (factory base and factory impl), which has space and downloading implications. 7. The requirement for the user to implement the default factory for non-boxed values is an unreasonable burden. It should be generated. 8. The automatic generation of a no-argument init() method on the value factory abstract class if there are no initializers declared in IDL is contrary to previously agreed OBV semantics and is not consistent with the OBV C++ mapping. Only explicitly declared IDL initializers should have init() methods. 9. The convenience create function takes an ORB parameter and performs a full factory lookup on that ORB. Although for some applications (e.g., using PSS) this may be necessary, in the vast majority of cases it is overkill. An alternative convenience create function that uses the default factory should also be provided. I will send a proposal in a separate note that solves these problems. Simon -- Simon C Nash, IBM Java Technology Centre, Hursley, UK MailPoint 146, x245156 Tel. 01962 815156 or +44-1962-815156 Internet: nash@hursley.ibm.com Notes mail: Simon Nash@ibmgb Return-Path: Sender: "George Scott" Date: Mon, 21 Sep 1998 14:38:07 -0700 From: "George M. Scott" Organization: Inprise Corporation To: Simon Nash CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Yet another OBV/Java language mapping proposal References: <36030382.B253EA3A@inprise.com> <360650AA.741CCB8F@hursley.ibm.com> Simon Nash wrote: > > George, > As you can imagine, I have a lot of comments on this. I'll start > with minor corrections to your proposal. Yes, and I imagnined you would have a lot more comments than you actually did. ;-) > 1. Your example shows class A having a method _ids() that is declared > as returning an array of Strings. However, it returns the result > of AHelper.id(), which is a String. There is no explanation of > how this method is used. As far as I can tell, this method should > be called _id and return a single String. That was a slight slip up. _ids is supposed to be a private static class memeber. The correct code should be: private static String[] _ids = { AHelper.id() }; public String[] _truncatable_ids() { return _ids; } > 2. In your example code, the getFactory method should be declared as > static, and its parameter name "orb" is missing. > > 3. Both "new" operators in ADefaultFactory should be for AImpl, not A. You are correct, sorry for the sloppiness. > Next, aspects of this proposal that need clarification: > > 4. The purpose of the read_Value method on BoxedValueFactory is not > clear. What is the situation for which the create_for_unmarshal > method cannot complete unmarshalling? It is needed for the case of boxing another value, which has cyclical references (these are corner cases, I admit). For example: valuetype List { long val; List next; } valuetype BoxedList List; As far as I know this is legal IDL, and if the list contains an indirection to itself, it cannot be correctly unmarshalled from the create_for_unmarshal case. > Problems with this proposal: > > 5. It requires reflective calls when marshalling boxed values > for non-primitive types. This is because the Java classes > generated for these boxed values do not implement the > StreamableValue interface with its _write method. With the > current spec, this is not a problem because the ORB's > marshalling code can always call the value helper instance's > write_Value method. That is why the BoxedValueFactory is always code generated by the compiler, the factory can perform the marshalling by calling upon the appropriate Helper for the boxed type. No reflection is necessary, and it is expected that most boxed types will not be values. > 6. Too many classes are generated. The current spec requires > Holder, Helper, and implementation classes only. I would be > willing to add one more class (the abstract base class) to > solve the tool issue of mixing generated code with user code, > and the ability to provide different implementations. However, > this proposal adds a further 2 classes (factory base and > factory impl), which has space and downloading implications. This mapping does add additional classes, but is consistent with the C++ mapping which we feel is important for CORBA users who often work in both languages. Furthermore, we feel that it is confusing to the user community to mix the notion of a factory class with the current notion of a Helper class. We feel the separation is warranted and provides a cleaner design. > 7. The requirement for the user to implement the default > factory for non-boxed values is an unreasonable burden. > It should be generated. This is a tools issue, an ORB vendor could always choose to generate a default factory for the user. > 8. The automatic generation of a no-argument init() method on the > value factory abstract class if there are no initializers > declared in IDL is contrary to previously agreed OBV semantics > and is not consistent with the OBV C++ mapping. Only explicitly > declared IDL initializers should have init() methods. Then I would say there is something wrong with the previously agreed OBV semantics and the OBV C++ mapping. In both C++ and Java when no constructors are declared, the compiler automatically generates a default no argument constructor. Considering that IDL valuetypes were modeled after C++/Java classes I don't see why OBV would want to go its own way. It also completely illogical to have no constructors for a value. How would a user possibly create such a value in the first place? If there is no way to create a value, then it certainly cannot be transmitted over the wire, unless you are proposing users create such values through some backdoor mechanism. > 9. The convenience create function takes an ORB parameter and > performs a full factory lookup on that ORB. Although for some > applications (e.g., using PSS) this may be necessary, in the > vast majority of cases it is overkill. An alternative > convenience create function that uses the default factory > should also be provided. This will result in an inconsistent system. What happens when the user call ORB.register_value_factory and changes the implementation of the value. Now when the ORB receives a value over-the-wire it will use the implementation which is registered with it, but if the user calls the create function they will receive a different implementation. With our proposal, it is not possible to have an inconsistent view (assuming nobody changes the factory in the middle of execution). > I will send a proposal in a separate note that solves these problems. My comments on your new proposal are in a separate message as well. George Return-Path: Date: Tue, 22 Sep 1998 08:49:05 +0100 From: Simon Nash Organization: IBM To: "George M. Scott" CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Yet another OBV/Java language mapping proposal References: <36030382.B253EA3A@inprise.com> <360650AA.741CCB8F@hursley.ibm.com> <3606C73F.655FBD20@inprise.com> George M. Scott wrote: > > Simon Nash wrote: > > > > George, > > As you can imagine, I have a lot of comments on this. I'll start > > with minor corrections to your proposal. > > Yes, and I imagnined you would have a lot more comments than you > actually > did. ;-) > Actually I did have more comments but I decided to "censor" them in the interests of keeping the discussion technical and constructive. You can imagine what they were.... > > 1. Your example shows class A having a method _ids() that is declared > > as returning an array of Strings. However, it returns the result > > of AHelper.id(), which is a String. There is no explanation of > > how this method is used. As far as I can tell, this method should > > be called _id and return a single String. > > That was a slight slip up. _ids is supposed to be a private static > class memeber. The correct code should be: > > private static String[] _ids = { > AHelper.id() > }; > > public String[] _truncatable_ids() { > return _ids; > } > > > 2. In your example code, the getFactory method should be declared as > > static, and its parameter name "orb" is missing. > > > > 3. Both "new" operators in ADefaultFactory should be for AImpl, not A. > > You are correct, sorry for the sloppiness. > > > Next, aspects of this proposal that need clarification: > > > > 4. The purpose of the read_Value method on BoxedValueFactory is not > > clear. What is the situation for which the create_for_unmarshal > > method cannot complete unmarshalling? > > It is needed for the case of boxing another value, which has cyclical > references (these are corner cases, I admit). For example: > > valuetype List { > long val; > List next; > } > > valuetype BoxedList List; > > As far as I know this is legal IDL, and if the list contains an indirection > to itself, it cannot be correctly unmarshalled from the > create_for_unmarshal case. > > > Problems with this proposal: > > > > 5. It requires reflective calls when marshalling boxed values > > for non-primitive types. This is because the Java classes > > generated for these boxed values do not implement the > > StreamableValue interface with its _write method. With the > > current spec, this is not a problem because the ORB's > > marshalling code can always call the value helper instance's > > write_Value method. > > That is why the BoxedValueFactory is always code generated by the > compiler, the factory can perform the marshalling by calling upon > the appropriate Helper for the boxed type. No > reflection is necessary, > and it is expected that most boxed types will not be values. > The problem occurs with marshalling, not unmarshalling. How do you expect a boxed string (a very common case) to be marshalled without reflection? Your proposed factory approach deals only with unmarshalling. > > 6. Too many classes are generated. The current spec requires > > Holder, Helper, and implementation classes only. I would be > > willing to add one more class (the abstract base class) to > > solve the tool issue of mixing generated code with user code, > > and the ability to provide different implementations. > However, > > this proposal adds a further 2 classes (factory base and > > factory impl), which has space and downloading implications. > > This mapping does add additional classes, but is consistent with the > C++ > mapping which we feel is important for CORBA users who often work in > both languages. > One of the advantages of CORBA programming in Java over CORBA programming in C++ is that it is considerably simpler. If consistency implies complexity, I'd prefer inconsistency and simplicity. > Furthermore, we feel that it is confusing to the user community to mix > the notion of a factory class with the current notion of a Helper class. > We feel the separation is warranted and provides a cleaner design. > This could be argued either way. The helper class is a collection of utility functions of various kinds. Some of these (e.g., narrow) are user APIs. Putting user-callable utility functions that create a value on the helper class seems consistent with this. > > 7. The requirement for the user to implement the default > > factory for non-boxed values is an unreasonable burden. > > It should be generated. > > This is a tools issue, an ORB vendor could always choose to generate > a default factory for the user. > And a default implementation? That could be a reasonable approach which combines convenience and flexibility. > > 8. The automatic generation of a no-argument init() method on the > > value factory abstract class if there are no initializers > > declared in IDL is contrary to previously agreed OBV semantics > > and is not consistent with the OBV C++ mapping. Only > explicitly > > declared IDL initializers should have init() methods. > > Then I would say there is something wrong with the previously agreed > OBV semantics and the OBV C++ mapping. In both C++ and Java when no > constructors are declared, the compiler automatically generates a > default > no argument constructor. Considering that IDL valuetypes were > modeled > after C++/Java classes I don't see why OBV would want to go its own > way. > One difference is that in Java I can declare a single private no-argument constructor to prevent any instances being created by client code using "new". This would still allow static methods of the class to create instances. With your proposal, there would be no way to completely turn off the public create mechanism for IDL valuetypes mapped to Java. > It also completely illogical to have no constructors for a value. > How would a user possibly create such a value in the first place? > If > there is no way to create a value, then it certainly cannot be > transmitted > over the wire, unless you are proposing users create such values > through > some backdoor mechanism. > I'd prefer to call it non-portable rather than backdoor. This was all hashed out and agreed (including by your company) in the original OBV submitter discussions. I see no reason to revisit this now. > > 9. The convenience create function takes an ORB parameter and > > performs a full factory lookup on that ORB. Although for some > > applications (e.g., using PSS) this may be necessary, in the > > vast majority of cases it is overkill. An alternative > > convenience create function that uses the default factory > > should also be provided. > > This will result in an inconsistent system. What happens when the > user > call ORB.register_value_factory and changes the implementation of > the > value. Now when the ORB receives a value over-the-wire it will use > the > implementation which is registered with it, but if the user calls > the > create function they will receive a different implementation. With > our > proposal, it is not possible to have an inconsistent view (assuming > nobody > changes the factory in the middle of execution). > There could also be multiple implementations registered with different ORB objects. I might receive values over two different IIOP connections (owned by different ORBs) and get different implementations. But is this a problem? As long as all the implementations of an IDL valuetype A are of Java type A, I should be able to deal with them uniformly and not care what their implementation type is. Why do you think it is a problem to have a mixture of implementations? Simon -- Simon C Nash, IBM Java Technology Centre, Hursley, UK MailPoint 146, x245156 Tel. 01962 815156 or +44-1962-815156 Internet: nash@hursley.ibm.com Notes mail: Simon Nash@ibmgb Return-Path: Sender: "George Scott" Date: Tue, 22 Sep 1998 10:02:36 -0700 From: "George M. Scott" Organization: Inprise Corporation To: Simon Nash CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Yet another OBV/Java language mapping proposal References: <36030382.B253EA3A@inprise.com> <360650AA.741CCB8F@hursley.ibm.com> <3606C73F.655FBD20@inprise.com> <36075671.6FD79BCA@hursley.ibm.com> Simon Nash wrote: > > George M. Scott wrote: > > That is why the BoxedValueFactory is always code generated by the > > compiler, the factory can perform the marshalling by calling upon > > the appropriate Helper for the boxed type. No > > reflection is necessary, > > and it is expected that most boxed types will not be values. > > > The problem occurs with marshalling, not unmarshalling. How do > you expect a boxed string (a very common case) to be marshalled > without reflection? Your proposed factory approach deals only > with unmarshalling. That was an oversight. To correct it, we can add a write_Value method to BoxedValueFactory. > > Furthermore, we feel that it is confusing to the user community to mix > > the notion of a factory class with the current notion of a Helper class. > > We feel the separation is warranted and provides a cleaner design. > > > This could be argued either way. The helper class is a collection of > utility functions of various kinds. Some of these (e.g., narrow) are > user APIs. Putting user-callable utility functions that create a value > on the helper class seems consistent with this. I agree it can be argued either way and it is a matter of personal preference. We are certainly willing to consider making the Factory base class the same as the Helper class, but my preference is to not do that. > > Then I would say there is something wrong with the previously agreed > > OBV semantics and the OBV C++ mapping. In both C++ and Java when no > > constructors are declared, the compiler automatically generates a default > > no argument constructor. Considering that IDL valuetypes were modeled > > after C++/Java classes I don't see why OBV would want to go its own way. > > > One difference is that in Java I can declare a single private > no-argument constructor to prevent any instances being created by > client code using "new". This would still allow static methods of > the class to create instances. With your proposal, there would be > no way to completely turn off the public create mechanism for IDL > valuetypes mapped to Java. This can also be done in C++, and is not a feature which is special to Java. I still find it ridiculous that we are going to define a data type in IDL which has no portably defined way to create an instance of that type. There is no other data type in IDL which has this property. > > It also completely illogical to have no constructors for a value. > > How would a user possibly create such a value in the first place? > If > > there is no way to create a value, then it certainly cannot be > transmitted > > over the wire, unless you are proposing users create such values > through > > some backdoor mechanism. > > > I'd prefer to call it non-portable rather than backdoor. This was > all hashed out and agreed (including by your company) in the > original > OBV submitter discussions. I see no reason to revisit this now. Simon, our companies agreed on a lot of things in the original OBV submission. But as it turns out we had to change our minds on most of those things. I don't see why this item should be excluded from reconsideration. > > > There could also be multiple implementations registered with > different ORB objects. I might receive values over two different > IIOP connections (owned by different ORBs) and get different > implementations. But is this a problem? As long as all the > implementations of an IDL valuetype A are of Java type A, I should > be able to deal with them uniformly and not care what their > implementation type is. Why do you think it is a problem to have > a mixture of implementations? 1. If the valuestypes are custom, then their on-the-wire format may differ. 2. The implementations may behave differently, since we have no way of specifying semantics in IDL. 3. For PSS, users may expect the same persistent store for the values they are manipulating, which is usually tied into the implementation. George Return-Path: Sender: "George Scott" Date: Fri, 25 Sep 1998 11:40:46 -0700 From: "George M. Scott" Organization: Inprise Corporation To: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Final OBV/Java mapping proposal References: <360B0CCF.67772F15@inprise.com> George M. Scott wrote: > > Below is an updated proposal for the OBV Java mapping, we hope to > vote > on this in tomorrow's conf. call. Since this proposal did not pass, we are withdrawaling this proposal from consideration by the next RTF. We feel this proposal would work, but was not, in our opinion, an "ideal" mapping. We will be submitting a new proposal in the coming weeks. George Return-Path: Sender: "George Scott" Date: Thu, 24 Sep 1998 20:23:59 -0700 From: "George M. Scott" Organization: Inprise Corporation To: obv-rtf@omg.org, java-rtf@omg.org Subject: Final OBV/Java mapping proposal Below is an updated proposal for the OBV Java mapping, we hope to vote on this in tomorrow's conf. call. Here are the current issues: 1. Java valuetypes cannot unmarshal recursive references to themselves. This is the same problem that occurs with custom valuetypes. 2. The current language mapping mixes both generated code with user written code in the same source file. This poses a very complex "tool" issue for IDL compilers which is unnecessarily complex. 3. Java valuetypes need a way to unmarshal the state of their base class. 4. The ValueHelper interface contains the method get_safe_base_ids, which is inconsistent with current OBV terminology. 5. The marshaling of boxed types should be considered carefully, because of the special casing required for boxed strings, and other boxed types. 6. The compiler should provide compile time enforcement of init() declarations. Here is our complete proposal: The following interfaces are added to org.omg.CORBA.portable: package org.omg.CORBA.portable; public interface ValueHelper { void read_Value(InputStream istream, java.io.Serializable obj); void write_Value(OutputStream ostream, java.io.Serializable obj); String[] get_truncatable_ids(); org.omg.CORBA.TypeCode get_type(); } public interface ValueFactory extends ValueHelper { java.io.Serializable create_for_unmarshal(InputStream is); } public interface IDLValueBase extends IDLEntity { ValueHelper _getHelper(); } The ValueHelper interface is implemented by all Helper classes for values. The methods are identical to the methods present in the current spec (the one adopted by the last RTF), except read_Value has been changed to take a Serializable and now return void. get_safe_base_ids has been renamed to get_truncatable_ids, and get_class and get_id have been removed. get_class was removed because it is no longer meaningful. get_id was removed because the same information can be obtained from calling get_truncatable_ids()[0], and is simply a redundant method which would have to be generated for all classes. The ValueFactory interface is the base interface for all value factories and is the native mapping of the IDL native type ValueFactory. It extends ValueHelper to allow for umarshalling of boxed values, and adds one additional method create_for_unmarshal() which returns a Serializable and takes an InputStream as parameter. The InputStream argument is normally ignored, except for those cases where some unmarshalling must occur before a Factory can create an instance of the object. This is the case, for example, for boxed strings and boxed wstrings. The IDLValueBase interface is the base interface for all non-abstract IDL valuetypes. This interface defines a single method _getHelper() which returns the ValueHelper associated with the valuetype. The method is called during marshalling/unmarshalling to get the correct Helper to marshal the valuetype's complete state. An IDL valuetype is now mapped to two Java classes, a value class and a factory interface. The factory interface is only generated if there are init delcarations present in the IDL valuetype. If no init declarations are present, the org.omg.CORBA.portable.ValueFactory interface is the base interface for the value factory. The value class is an abstract class which implements the IDLValueBase interface. There is a protected data member in the abstract class for every private data member declared in IDL and there is a public data member for every public data member declared in IDL. There is an absract method declaration for every method declared in the valuetype. Concrete valuetype inheritance is mirrored in the Java class hierarchy. If there are inits present in IDL, then an interface named "ValueFactory" is generated which extends org.omg.CORBA.portable.ValueFactory. The generated factory interface will have a create method for each init declared in IDL. For example: // IDL valuetype A { public long l; private short s; void foo(); init(long l); }; would map to the following abstract class: abstract public class A implements org.omg.CORBA.portable.IDLValueBase { public int l; protected short s; abstract public void foo(); public _getHelper() { return AHelper.get_instance(); } } And the Factory interface: public interface AValueFactory extends org.omg.CORBA.portable.ValueFactory { A create(int l); } The user must provide concrete implementations of both the value and the value factory. By convention the name of the factory should be the name of the value appeneded by DefaultFactory for the ORB to be able to find a default factory automatically. If the name is some other name, then the user must explicitly register the factory with ORB using ORB.register_value_factory(). The user written factory must extend the Helper class associated with the value and implement the valuetype's factory interface (if there are inits) or the org.omg.CORBA.portable.ValueFactory interface. Note, this is essentially the same as the current model for C++. For example the following is a valid implementation of A: class AImpl extends A { A(int l) { ... } A() { ... } public void foo() { ... } } class ADefaultFactory extends AHelper implements AValueFactory { public java.io.Serializable create_for_unmarshal(InputStream is) { return new AImpl(); } public A init(int l) { return new AImpl(l); } } ---------------------------------------- In addition to the value and factory class, additional static methods are generated on the Helper if the valuetype contains init declarations. These additional methods are intended to make it easy for the user to create values. The additional generated methods are: - setValueFactory() - changes the default value factory used when the users calls one of the static create method. This method changes the default factory only for the helper and does not register the factory with the ORB. - getValueFactory() - returns the current default factory which was registered using setValueFactory. If setValueFactory has never been called it will attempt to load the DefaultFactory class. If this class is not found, this method throws BAD_PARAM (the same exception returned by a failed lookup in ORB.lookup_value_factory()). - create() - There is one create method generated for each init declared in IDL. These methods simply call getValueFactory() and then call the appropriate create method on the ValueFactory. public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... private static AValueFactory _factory = null; public static void setValueFactory(AValueFactory factory) { _factory = factory; } public static AValueFactory getValueFactory() { if (_factory == null) { synchronized(AHelper.class) { if (_factory == null) { try { Class cl = AHelper.class.getClassLoader().loadClass("ADefaultFactory"); _factory = cl.newInstance(); } catch(Exception e) { throw new org.omg.CORBA.BAD_PARAM(); } } } } return _factory; } public static A create(int l) { return getValueFactory().create(l); } } For example, a user would create an instance of A via the following call: A a = AHelper.create(35); ----------------------------------------------- Boxed values are treated specially, due to the mapping of boxed values to Java. For example: valuetype BoxedString string; Generally, the type being boxed will not be a valuetype, so special processing is required. The above example will map to java.lang.String, and the compiler will automatically generate a default factory for boxed values (the user does not write the factory for boxed values, in fact no user code is required for any boxed values): public class BoxedStringDefaultFactory extends BoxedStringHelper implements org.omg.CORBA.portable.ValueFactory { public java.io.Serializable create_for_unmarshal(org.omg.CORBA.portable.InputStream is) { return is.read_string(); } } ----------------------------------------------- The following is an example of a mapping for valuetype inheritance. Note, that the Helpers shown below do not contain exception handling code. Also, please note that value factories are never inheirted, because init declarations are not inherited. // IDL valuetype A { public long l; }; valuetype B : A { public short s; }; This would generate the following classes: abstract public class A implements org.omg.CORBA.portable.IDLValueBase { public int l; public org.omg.CORBA.portable.ValueHelper _getHelper() { return AHelper.get_instance(); } } abstract public class B extends A { public short s; public org.omg.CORBA.portable.ValueHelper _getHelper() { return BHelper.get_instance(); } } // Java public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... public void read_Value(org.omg.CORBA.portable.InputStream _input, java.io.Serializable value) { ((A)value).l = _input.read_long(); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable value) { _output.write_long((A)value).l); } public static A read(org.omg.CORBA.portable.InputStream _input) { return (A) _input.read_Value(get_instance()); } public static void write(org.omg.CORBA.portable.OutputStream _output, A value) { _output.write_Value(value, get_instance()); } } public class BHelper implements org.omg.CORBA.portable.ValueHelper { ... public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable value) { AHelper.get_instance().read_Value(_input, value); ((B)value).s = _input.read_short(); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable value) { AHelper.get_instance().write_Value(_output, value); _output.write_short(((B)value).s); } public static B read(org.omg.CORBA.portable.InputStream _input) { return (B) _input.read_Value(get_instance()); } public static void write(org.omg.CORBA.portable.OutputStream _output, B value) { _output.write_Value(value, get_instance()); } } Our proposal addressed our seven issues: 1. Java values can now correctly support recursive marshalling of themselves. This is supported through the create_for_unmarshal method which allows the ORB to create an instance of the value before unmarshalling allowing the ORB to do all necessary bookkeeping. 2. Generated code is now separated from user code. All generated code for a value is now isolated in an abstract base class and a factory interface representing the init operations. 3. Base class marshalling is handled by having the Helper call the base class Helper's get_instance() method and then invoking the appropriate marshalling routine. 4. get_safe_base_ids has been renamed get_truncatable_ids. 5. Boxed value are treated specially, by the compiler generating a default factory and allowing create_for_unmarshal to partially (or completely) unmarshal object state. 6. inits are now enforced through the compiler via an interface, which the user must implement. George Return-Path: Date: Mon, 21 Sep 1998 17:51:21 +0100 From: Simon Nash Organization: IBM To: obv-rtf@omg.org, java-rtf@omg.org Subject: Alternative proposal for OBV/Java mapping In a separate note I have pointed out some problems with the latest OBV/Java proposal from George. Here is an alternative proposal that builds upon previous discussions and proposals and solves these problems. It is simpler than George's proposal, does not require so many classes (generated or user-written) and treats boxed and regular valuetypes in a uniform way. The org.omg.CORBA.portable.Helper interface is removed from the mapping. Its use adds considerable space overhead to an ORB implementation and all users of IDL to support an optimization of an RMI-IIOP corner case. RMI-IIOP can fully function without this interface, and the space overhead cannot be justified by the time savings for supporting this optimization. The org.omg.CORBA.portable.ValueHelper interface is redefined as follows: package org.omg.CORBA.portable; public interface ValueHelper { void read_Value(InputStream istream, java.io.Serializable obj); void write_Value(OutputStream ostream, java.io.Serializable obj); java.io.Serializable create_for_unmarshal(InputStream istream); Class get_class(); String[] get_truncatable_ids(); String get_id(); org.omg.CORBA.TypeCode get_type(); } The methods get_id, and get_type have been moved from Helper to ValueHelper. The method read_Object and write_Object, which were defined on Helper are no longer needed and hence removed. The get_safe_base_ids method has been renamed get_truncatable_ids. The method create_for_unmarshal has been created to allow the helper to create an object so that it can be unmarshalled (this is identical to the C++ mapping). The read_Value signature has changed to no longer return a Serializable, and is instead passed the instance into which it should demarshal the state. An IDL valuetype is now mapped to two Java classes, an abstract class and an implementation class. For example: // IDL valuetype A { public long l; private short s; void foo(); init(long l); }; would now map to the following abstract class: public abstract class A implements org.omg.CORBA.portable.IDLEntity { public int l; protected short s; public abstract void foo(); abstract void _init(int l); } The implementer would have to provide a concrete implementation class which extends the abstract base class. An IDL compiler could, of course, generate a "sample" implementation. No constructors are needed for the implementation class as the default no-argument constructor is suitable for use by the create_for_unmarshal method. For example, the following is a valid implementation of A: class AImpl extends A { void _init(int l) { ... } public void foo() { ... } } Instances of value types are created using a factory mechanism. The generated Helper class is the default factory, but alternative factories can be provided by the implementer by subclassing the Helper class, overriding create_for_umarshal to specify a different implementation class, and registering the subclass with the ORB. For value types with initializers, corresponding static create methods are generated in the Helper class. The implementation class for the default factory is called Impl, where is the name of the valuetype. The generated Helper class contains the following code: public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... public java.io.Serializable create_for_unmarshal (org.omg.CORBA.portable.InputStream _input) { return new AImpl(); // default implementation } public static A create(int l) { A newA = (A) create_for_unmarshal(null); newA._init(l); return newA; } public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable obj) { ((A) obj).l = _input.read_long(); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable obj) { _output.write_long(((A) obj).l); } } For a value derived from A, such as B, the generated Helper class contains the following code to marshal its base class state: public class BHelper implements org.omg.CORBA.portable.ValueHelper { ... static private AHelper baseHelper = AHelper.getInstance(); public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable obj) { baseHelper.read_Value(_input, obj); ((B) obj).s = _input.read_short(); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable obj) { baseHelper.write_Value(_output, obj); _output.write_short(((B) obj).s); } } A boxed value is treated specially, due to the mapping of boxed values to Java. For example: valuetype BoxedString string; Generally, the type being boxed will not be a valuetype, so special processing is required, epsecially for boxed strings, arrays, and sequences. The above example will map to java.lang.String, and the compiler will generate the following code in the boxed string's Helper class: public class BoxedStringHelper { public java.io.Serializable create_for_unmarshal (org.omg.CORBA.portable.InputStream is) { return is.read_string(); } public void read_Value(org.omg.CORBA.portable.InputStream is, java.io.Serializable value) { // do nothing for this case. } } Simon -- Simon C Nash, IBM Java Technology Centre, Hursley, UK MailPoint 146, x245156 Tel. 01962 815156 or +44-1962-815156 Internet: nash@hursley.ibm.com Notes mail: Simon Nash@ibmgb Return-Path: Sender: "George Scott" Date: Mon, 21 Sep 1998 15:20:36 -0700 From: "George M. Scott" Organization: Inprise Corporation To: Simon Nash CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Alternative proposal for OBV/Java mapping References: <36068409.A02AB92E@hursley.ibm.com> Simon Nash wrote: > > Instances of value types are created using a factory mechanism. > The generated Helper class is the default factory, but alternative > factories can be provided by the implementer by subclassing the > Helper class, overriding create_for_umarshal to specify a different > implementation class, and registering the subclass with the ORB. > For value types with initializers, corresponding static create > methods > are generated in the Helper class. The code you have shown below does not illustrate how this would work correctly. For example, you have a static create method which is calling a non-static method (create_for_unmarshal) which can potentially be overriden by the user. How does the static create method find the correct Helper instance to invoke? How is it assured of getting the same factory the ORB is using for unmarshalling? Simon, we have internally been down this path and decided against it for several reasons: 1. The Helper class contains compile time references to the user's implementation class. This forces such a class to be present at compile time, even if it is not needed or will not be used at runtime. 2. It forces the user to implement their object in the same package as the generated code if they want to use default (implicit) registration of value factories. This is expected to be a problem for a number of reasons: a. The implementation of a value may be closely tied to another package and may need to be located in the other package. b. Users typically generate code into one package, yet use another package for implementation. This model is less error prone and less confusing to users, in our experience. c. Implementations of any "standard values" which may appear in the org.omg.* packages should have their implementations in a separate package and should be forced to manually register their factories. If this is the case, then the generated code will contain a reference to a non-existent class which seems very peculiar. We expect IDL compilers to be able to generate a number a default factory "patterns" for the user for the majority of cases, which would aid the user in accomplishing the above. 3. The user's implementation flexibility is hampered. The user is forced to write a public default constructor and implement the init methods. With the factory approach the user has a large amount of flexibility in how to actually construct the value. The factory's create method could directly call constructors, invoke methods on the value, or call a completely different set of classes/methods to create the value. George Return-Path: Date: Mon, 21 Sep 1998 16:50:52 -0700 From: "Vijaykumar Natarajan" Organization: Inprise Corporation X-Accept-Language: en To: Simon Nash CC: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: Alternative proposal for OBV/Java mapping References: <36068409.A02AB92E@hursley.ibm.com> > > > > An IDL valuetype is now mapped to two Java classes, an abstract class > and an implementation class. For example: > > // IDL > valuetype A { > public long l; > private short s; > void foo(); > init(long l); > }; > > would now map to the following abstract class: > > public abstract class A implements org.omg.CORBA.portable.IDLEntity { > public int l; > protected short s; > > public abstract void foo(); > > abstract void _init(int l); > } > > The implementer would have to provide a concrete implementation class > which extends the abstract base class. An IDL compiler could, of course, > generate a "sample" implementation. No constructors are needed for > the implementation class as the default no-argument constructor is > suitable for use by the create_for_unmarshal method. > > For example, the following is a valid implementation of A: > > class AImpl extends A { > > void _init(int l) { ... } > > public void foo() { ... } > > } > Hi Simon, This mechanism of mapping initializers has the unfortunate side effect of inheriting initializers from base values. So, a value has to implement all base value inits. And that was one of the many reasons why the factory approach was used in our proposal, so that the factory could deal with implementation constructors, and not methods, unless the user wanted to. Vijay Date: Thu, 18 Mar 1999 02:22:25 +0000 From: Simon Nash Organization: IBM To: Vijay Natarajan CC: George Scott , Jeff Mischkinsky , java-rtf@omg.org Subject: Issue 1980 - Proposed amendments Vijay, I would like to propose some amendments to the Inprise proposal for issue 1980. I hope Inprise will be able to accept them as friendly amendments. They address a number of issues that I have raised with the proposal, and I believe they do this in a simple and elegant way. 1. Change ValueFactory to be public interface ValueFactory { java.io.Serializable read_value(InputStream is); } 2. Change BoxedValueHelper to be public interface BoxedValueHelper extends ValueFactory { void write_value(OutputStream os. java.io.Serializable value); java.lang.String get_id(); } These two changes unify the creation and demarshalling of boxed values and regular values with the same read_value(InputStream) method being called in both cases. They also solve the safety problem that the current create_for_unmarshal creates. 3. Remove the public getValueFactory method on the value helper class. This is not needed, since ORB.lookup_value_factory can easily be used with little if any loss of convenience. This saves code in value helpers. 4. Change the name of the generated factory interface from xxValueFactory to xxFactory. The proposal is currently inconsistent on this point. 5. Add a method void read_value(java.io.Serializable value) { ... } to InputStream, and show the read_value code in the helper calling this method. 6. Remove the statement that the ValueHandler is used when an RMI: repository ID is received. The ValueHandler must only be called for non-IDLEntity types. Just because the repid is RMI: does not mean that the class to be demarshalled is not an IDLEntity. 7. Add SerializableHolder to allow ValueBase to be used as an out or inout parameter. 8. The proposal needs to say whether abstract value types extend ValueBase or IDLEntity. It currently says neither. Note that I did not ask for the current methods that take a ValueHelper to be retained. This is because if the above changes are made, ORB vendors can if they wish ship a compliant product that supports the ValueHelper mechanism without the need for additional APIs with ValueHelper signatures (deprecated or otherwise). All that needs to be done is to make the above changes and redefine ValueHelper as extending BoxedValueHelper (not unreasonable). Then the new register_value_factory and lookup_value_factory methods could take and return a ValueHelper, since ValueHelper is a subtype of ValueFactory. Also, the new stream read_value and write_value method overloads that take a BoxedValueHelper could be passed a ValueHelper, since ValueHelper is a subtype of BoxedValueHelper. ORB vendors would not have to support the ValueHelper mechanism but there would be nothing to stop an ORB vendor who needs to provide a migration path from the current spec to the new spec from shipping a runtime that can handle the ValueHelper case as well as the new mechanisms. I will send out detailed edits tomorrow but I wanted to get the major technical points out today so anyone working late(??) would have more time to consider them. I also have some other editorial comments which I will send out tomorrow. I think it would be helpful to have an RTF call tomnorrow to discuss this proposal before we vote. Jeff, can you schedule this? I can do pretty much any time, but I would prefer it to be before noon PST if possible. Simon -- Simon C Nash, Technology Architect, IBM Java Technology Centre Tel. +44-1962-815156 Fax +44-1962-818999 Hursley, England Internet: nash@hursley.ibm.com Lotus Notes: Simon Nash@ibmgb Date: Wed, 17 Mar 1999 23:48:51 -0800 From: "George Scott" Organization: Inprise Corporation X-Accept-Language: en To: Simon Nash CC: Vijay Natarajan , Jeff Mischkinsky , java-rtf@omg.org Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> Simon Nash wrote: > > Vijay, > I would like to propose some amendments to the Inprise proposal for > issue 1980. I hope Inprise will be able to accept them as friendly > amendments. They address a number of issues that I have raised with > the proposal, and I believe they do this in a simple and elegant > way. Simon, It is very clever how you have twisted our proposal to convert it back into the current draft spec. But, it simply does not solve the problems we are trying to solve. See comments below. > 1. Change ValueFactory to be > public interface ValueFactory { > java.io.Serializable read_value(InputStream is); > } This interface is supposed to be implemented by the user. You are now expecting the user to write their own marshalling code? Do you want the compiler to somehow mix and match user code with generated code. This is one of the things we are trying to avoid with our new proposal. The create_for_unmarshal method is very simple, it allows the user to write code which will create an instance of the value which can be initialized by the marshaling process. I do not understand the problem with this method being public. This is the way it is specified in C++, and I've yet to hear screams from anybody about the C++ mapping for valuetypes. Why is this such an issue for Java? Considering that many of our customers work in both Java and C++, I would imagine they would find it a bit easier to write valuetypes if the design patterns are the same for both languages. Furthermore, this proposal assumes that state information is stored somewhere in the stream between ORB upcalls to the ValueFactory and the downcall to the new read_value() method. This can be quite difficult for ORB vendors who allow multi-threaded access to their marshalling streams. Our current proposal of two upcalls by the ORB allows all state to be stored on the Java stack and not in a member variable or static variable of some class. > 2. Change BoxedValueHelper to be > public interface BoxedValueHelper extends ValueFactory { > void write_value(OutputStream os. java.io.Serializable > value); > java.lang.String get_id(); > } > These two changes unify the creation and demarshalling of boxed > values > and regular values with the same read_value(InputStream) method > being > called in both cases. They also solve the safety problem that > the > current create_for_unmarshal creates. Considering we can't accept your first ammendement, then this certainly doesn't make sense without that change. > 3. Remove the public getValueFactory method on the value helper class. > This is not needed, since ORB.lookup_value_factory can easily be used > with little if any loss of convenience. This saves code in value helpers. So rather than put this code in one place, I must now distribute it all over my application? I think the cost of this is in the Helper is minimal and adds true value to users. We can't agree to this ammendment. > 4. Change the name of the generated factory interface from xxValueFactory > to xxFactory. The proposal is currently inconsistent on this point. I couldn't find the inconsistency you are referring to, if you could point out where it is inconsistent we will correct the problem. However, we do prefer xxValueFactory, which is what is used in the examples. > 5. Add a method > void read_value(java.io.Serializable value) { ... } > to InputStream, and show the read_value code in the helper > calling > this method. Since we don't agree with item number one, this isn't appropriate. > 6. Remove the statement that the ValueHandler is used when an RMI: > repository ID is received. The ValueHandler must only be called > for non-IDLEntity types. Just because the repid is RMI: does not > mean that the class to be demarshalled is not an IDLEntity. I'll let Vijay comment on this one. > 7. Add SerializableHolder to allow ValueBase to be used as an out or > inout parameter. Agreed. We should add a org.omg.CORBA.ValueBaseHolder class which follows the templates of other primitive holder types in the IDL/Java mapping. While we're add it we should also add org.omg.CORBA.AbstractBaseHolder. > 8. The proposal needs to say whether abstract value types extend ValueBase > or IDLEntity. It currently says neither. I'll let Vijay comment on this one as well. George Date: Thu, 18 Mar 1999 00:51:07 -0800 From: "Vijaykumar Natarajan" X-Accept-Language: en To: Simon Nash CC: George Scott , Jeff Mischkinsky , java-rtf@omg.org Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> Hi Simon, Simon Nash wrote: > Vijay, > I would like to propose some amendments to the Inprise proposal for > issue 1980. I hope Inprise will be able to accept them as friendly > amendments. They address a number of issues that I have raised with > the proposal, and I believe they do this in a simple and elegant > way. > > 1. Change ValueFactory to be > public interface ValueFactory { > java.io.Serializable read_value(InputStream is); > } This implies one extra upcall to the input stream to unmarshal a value, in addition to the extra complexity of "magically" carrying over the offset between two calls. It seems to me that there is a simpler way to achieve the ability to support the ValueHelper based mapping, without changing the APIs. Here's how. Given the current APIs. the interface public interface ValueFactory { java.io.Serializable create_for_unmarshal(); }; and the interface public interface BoxedValueFactory { java.io.Serializable read_value(InputStream is); void write_value(OutputStream os, java.io.Serializable value); String get_id(); }; the ValueHelper interface for any orb that wishes to support it could be defined as public interface ValueHelper extends ValueFactory, BoxedValueFactory { java.lang.Class get_class(); ... all the other methods }; This would still achieve the ability to use the orb value factory registering APIs and the stream's read_value which takes the BoxedValueHelper. Also, note that what we proposed in java for create_for_unmarshal is identical to the C++ mapping. > 2. Change BoxedValueHelper to be > public interface BoxedValueHelper extends ValueFactory { > void write_value(OutputStream os. java.io.Serializable > value); > java.lang.String get_id(); > } > These two changes unify the creation and demarshalling of boxed > values > and regular values with the same read_value(InputStream) method > being > called in both cases. They also solve the safety problem that > the > current create_for_unmarshal creates. > 3. Remove the public getValueFactory method on the value helper class. > This is not needed, since ORB.lookup_value_factory can easily be used > with little if any loss of convenience. This saves code in value helpers. OK! > 4. Change the name of the generated factory interface from xxValueFactory > to xxFactory. The proposal is currently inconsistent on this point. > > 5. Add a method > void read_value(java.io.Serializable value) { ... } > to InputStream, and show the read_value code in the helper calling > this method. > > 6. Remove the statement that the ValueHandler is used when an RMI: > repository ID is received. The ValueHandler must only be called > for non-IDLEntity types. Just because the repid is RMI: does not > mean that the class to be demarshalled is not an IDLEntity. You are correct. Can you suggest better words? > 7. Add SerializableHolder to allow ValueBase to be used as an out or > inout parameter. Yup, gotta have that! > 8. The proposal needs to say whether abstract value types extend ValueBase > or IDLEntity. It currently says neither. That is correct. This is to ensure that there is no direct implementation of the abstract value type interface that masquerades as an idl entity. All instances will be instances of a concrete value type which will implement the IDLEntity interface. > Note that I did not ask for the current methods that take a ValueHelper > to be retained. This is because if the above changes are made, ORB vendors > can if they wish ship a compliant product that supports the ValueHelper > mechanism without the need for additional APIs with ValueHelper signatures > (deprecated or otherwise). > > All that needs to be done is to make the above changes and redefine > ValueHelper as extending BoxedValueHelper (not unreasonable). Then the > new register_value_factory and lookup_value_factory methods could take > and return a ValueHelper, since ValueHelper is a subtype of ValueFactory. > Also, the new stream read_value and write_value method overloads that take > a BoxedValueHelper could be passed a ValueHelper, since ValueHelper is a > subtype of BoxedValueHelper. ORB vendors would not have to support the > ValueHelper mechanism but there would be nothing to stop an ORB vendor > who needs to provide a migration path from the current spec to the new > spec from shipping a runtime that can handle the ValueHelper case as well > as the new mechanisms. Given the new suggestion I made, all the above will still be possible, and an ORB that wishes to could still support the ValueHelper mechanism without changes to the APIs. Hope this satisifies your concern. Thanks, Vijay Date: Thu, 18 Mar 1999 10:02:16 +0000 From: Simon Nash Organization: IBM To: George Scott CC: Vijay Natarajan , Jeff Mischkinsky , java-rtf@omg.org, David Heisser , Ken Cavanaugh Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> <36F0AFE3.9B21640D@inprise.com> George, George Scott wrote: > > Simon Nash wrote: > > > > Vijay, > > I would like to propose some amendments to the Inprise proposal > for > > issue 1980. I hope Inprise will be able to accept them as > friendly > > amendments. They address a number of issues that I have raised > with > > the proposal, and I believe they do this in a simple and elegant > way. > > Simon, > > It is very clever how you have twisted our proposal to convert it > back > into the current draft spec. But, it simply does not solve the > problems > we are trying to solve. See comments below. > > > 1. Change ValueFactory to be > > public interface ValueFactory { > > java.io.Serializable read_value(InputStream is); > > } > > This interface is supposed to be implemented by the user. You are > now > expecting the user to write their own marshalling code? Do you want > the compiler to somehow mix and match user code with generated code. > This is one of the things we are trying to avoid with our new > proposal. > I am hoping this is just a misunderstanding of what I am proposing. There is no need to mix and match user code with generated code, or > for the user to write marshalling code. The only thing the user has to do is add a line to a method he is already writing in a class he is > already writing. Instead of: public class FooDefaultFactory implements ValueFactory { public java.io.Serializable create_for_unmarshal() { return new FooImpl(); // example code } } he would write: public class FooDefaultFactory implements ValueFactory { public java.io.Serializable read_value(InputStream is) { java.io.Serializable value = new FooImpl(); // example code is.read_value(value); return value; } } Because of the separate declaration and return lines, this expands the method from one line to three. If you are concerned about this, the signature of my proposed new InputStream.read_value(value) method could be changed to return a value (consistent with other read_value methods) and the user-written code then becomes: public class FooDefaultFactory implements ValueFactory { public java.io.Serializable read_value(InputStream is) { return is.read_value(new FooImpl()); // example code } } > The create_for_unmarshal method is very simple, it allows the user to write > code which will create an instance of the value which can be initialized > by the marshaling process. I do not understand the problem with this method > being public. This is the way it is specified in C++, and I've yet to hear > screams from anybody about the C++ mapping for valuetypes. Why is this such > an issue for Java? Considering that many of our customers work in both > Java and C++, I would imagine they would find it a bit easier to write > valuetypes if the design patterns are the same for both languages. > The create_for_unmarshal method is not public in C++. It is private. The ORB calls it using the C++ "friend" mechanism. This mechanism is not available in Java, so some other solution to the safety issue is needed. I believe my proposal solves this problem with the minimum possible impact to the user. There are many differences between C++ programming and Java programming, and people who are smart enough to do both of these are not going to have a problem with this minor difference. > Furthermore, this proposal assumes that state information is stored > somewhere in the stream between ORB upcalls to the ValueFactory and > the downcall to the new read_value() method. This can be quite > difficult for ORB vendors who allow multi-threaded access to their > marshalling streams. Our current proposal of two upcalls by the ORB > allows all state to be stored on the Java stack and not in a member > variable or static variable of some class. > Clearly it cannot be stored in a static variable. However, there is no problem with storing it in a member variable. The stream must > maintain a lot of other information in member variables, including the stream > buffer and pointer and the indirection table so that it can deal with > read_value callbacks from the Streamable._read method. So it is not correct to say that your current proposal allows all state to be stored on the Java stack. My proposal can be supported by adding one more variable (the value tag offset for the value currently being demarshalled) to the existing per-stream instance data. > > 2. Change BoxedValueHelper to be > > public interface BoxedValueHelper extends ValueFactory { > > void write_value(OutputStream os. java.io.Serializable > value); > > java.lang.String get_id(); > > } > > These two changes unify the creation and demarshalling of boxed > values > > and regular values with the same read_value(InputStream) method > being > > called in both cases. They also solve the safety problem that > the > > current create_for_unmarshal creates. > > Considering we can't accept your first ammendement, then this > certainly doesn't > make sense without that change. > > > 3. Remove the public getValueFactory method on the value helper > class. > > This is not needed, since ORB.lookup_value_factory can easily > be used > > with little if any loss of convenience. This saves code in > value helpers. > > So rather than put this code in one place, I must now distribute it > all over > my application? I think the cost of this is in the Helper is > minimal and > adds true value to users. We can't agree to this ammendment. > I don't understand this response. Instead of the user writing FooHelper.getValueFactory(orb); they write instead orb.lookupValueFactory(Foohelper.id()) Why provide two different ways of doing exactly the same thing? It is hardly a convenience issue since they are both one line of code. > > 4. Change the name of the generated factory interface from xxValueFactory > > to xxFactory. The proposal is currently inconsistent on this point. > > I couldn't find the inconsistency you are referring to, if you could point > out where it is inconsistent we will correct the problem. However, we do > prefer xxValueFactory, which is what is used in the examples. > The examples use xxValueFactory but the normative text uses xxFactory. See the words for 25.13.2. BTW, there is a typo here. It says a Java class with the suffix "Factory" but it means a Java interface. There is no required suffix for the user-written factory class. > > 5. Add a method > > void read_value(java.io.Serializable value) { ... } > > to InputStream, and show the read_value code in the helper > calling > > this method. > > Since we don't agree with item number one, this isn't appropriate. > > > 6. Remove the statement that the ValueHandler is used when an RMI: > > repository ID is received. The ValueHandler must only be > called > > for non-IDLEntity types. Just because the repid is RMI: does > not > > mean that the class to be demarshalled is not an IDLEntity. > > I'll let Vijay comment on this one. > > > 7. Add SerializableHolder to allow ValueBase to be used as an out > or > > inout parameter. > > Agreed. We should add a org.omg.CORBA.ValueBaseHolder class which > follows > the templates of other primitive holder types in the IDL/Java > mapping. > While we're add it we should also add > org.omg.CORBA.AbstractBaseHolder. > These names are fine with me. > > 8. The proposal needs to say whether abstract value types extend ValueBase > > or IDLEntity. It currently says neither. > > I'll let Vijay comment on this one as well. > > George Coming back to issue 1, and the others (2 and 5) that are coupled to this as you say, I believe we have a choice. Either we could accept these three changes to the proposal, which allow compliant products to not ship any APIs that refer to the ValueHelper type, or we could do a "stapled" spec that includes both new and old APIs. With the "stapled" approach, it may be acceptable to mark the old APIs as deprecated as long as it is a compliance requirement for all ORB vendors to ship the signatures for two years, which is what we did when ORB.connect and ORB.disconnect were deprecated. The reason that this is so important to IBM is that if we do not have a single common set of org.omg.CORBA_2_3 APIs that can be shipped in different vendors' ORBs, we will be in the situation where a user cannot have the IBM ORB and the Inprise ORB on the classpath at the same time. Suppose the stream methods were to be removed from the spec entirely, and Inprise shipped an ORB containing stream API classes that omitted these APIs. If this ORB's jar were first in the classpath, the IBM ORB could not function correctly because it would attempt to call these nonexistent methods. So IBM's position is that it prefers the first approach (amended) because it solves other issues and avoids a "stapled" spec with a number of deprecated methods. However, if after discussion on our call today, this is still not acceptable to Inprise, then IBM will accept the "stapled" approach with deprecated API methods that are required to be shipped by compliant ORBs. However, IBM cannot accept a proposal that includes neither of the above, because of the severe impact it will have on its ability to deliver a product that can coexist with other compliant ORBs. Simon -- Simon C Nash, Technology Architect, IBM Java Technology Centre Tel. +44-1962-815156 Fax +44-1962-818999 Hursley, England Internet: nash@hursley.ibm.com Lotus Notes: Simon Nash@ibmgb Date: Thu, 18 Mar 1999 10:44:54 +0000 From: Simon Nash Organization: IBM To: Vijaykumar Natarajan CC: George Scott , Jeff Mischkinsky , java-rtf@omg.org Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> <36F0BE7B.85403518@inprise.com> Vijay, Vijaykumar Natarajan wrote: > > Hi Simon, > > Simon Nash wrote: > > > Vijay, > > I would like to propose some amendments to the Inprise proposal > for > > issue 1980. I hope Inprise will be able to accept them as > friendly > > amendments. They address a number of issues that I have raised > with > > the proposal, and I believe they do this in a simple and elegant > way. > > > > 1. Change ValueFactory to be > > public interface ValueFactory { > > java.io.Serializable read_value(InputStream is); > > } > > This implies one extra upcall to the input stream to unmarshal a > value, in > addition to the extra complexity of "magically" carrying over the > offset between > two calls. > There is an extra upcall. I already responded to George about > maintaining the offet information. This can be stored as an instance variable of the > stream without any "complexity" or "magic". Just set it before calling the > factory's read_value and test it in the stream's read_value(value) upcall. You > already need to maintain this state as a stack variable, so there is no extra > code, just a declaration change. > It seems to me that there is a simpler way to achieve the ability to support the > ValueHelper based mapping, without changing the APIs. Here's how. > > Given the current APIs. the interface > public interface ValueFactory { > java.io.Serializable create_for_unmarshal(); > }; > and the interface > public interface BoxedValueFactory { > java.io.Serializable read_value(InputStream is); > void write_value(OutputStream os, java.io.Serializable value); > String get_id(); > }; > > the ValueHelper interface for any orb that wishes to support it could be defined > as > public interface ValueHelper extends ValueFactory, BoxedValueFactory { > java.lang.Class get_class(); > ... all the other methods > }; > This does not work, because it requires the generated value helpers to have an implementation for create_for_unmarshal(). > This would still achieve the ability to use the orb value factory registering > APIs and the > stream's read_value which takes the BoxedValueHelper. > > Also, note that what we proposed in java for create_for_unmarshal is identical to > the C++ mapping. > Except that it's private in C++ and public in Java!! > > 2. Change BoxedValueHelper to be > > public interface BoxedValueHelper extends ValueFactory { > > void write_value(OutputStream os. java.io.Serializable > value); > > java.lang.String get_id(); > > } > > These two changes unify the creation and demarshalling of boxed > values > > and regular values with the same read_value(InputStream) method > being > > called in both cases. They also solve the safety problem that > the > > current create_for_unmarshal creates. > > > 3. Remove the public getValueFactory method on the value helper > class. > > This is not needed, since ORB.lookup_value_factory can easily > be used > > with little if any loss of convenience. This saves code in > value helpers. > > OK! > > > 4. Change the name of the generated factory interface from > xxValueFactory > > to xxFactory. The proposal is currently inconsistent on this > point. > > > > 5. Add a method > > void read_value(java.io.Serializable value) { ... } > > to InputStream, and show the read_value code in the helper > calling > > this method. > > > > 6. Remove the statement that the ValueHandler is used when an RMI: > > repository ID is received. The ValueHandler must only be > called > > for non-IDLEntity types. Just because the repid is RMI: does > not > > mean that the class to be demarshalled is not an IDLEntity. > > You are correct. Can you suggest better words? > > > 7. Add SerializableHolder to allow ValueBase to be used as an out > or > > inout parameter. > > Yup, gotta have that! > > > 8. The proposal needs to say whether abstract value types extend > ValueBase > > or IDLEntity. It currently says neither. > > That is correct. This is to ensure that there is no direct > implementation of the > abstract value type interface > that masquerades as an idl entity. All instances will be instances > of a concrete > value type which will implement the IDLEntity interface. > This is a serious issue for the reverse mapping. We need to be able > to detect Java interface types that were mapped from IDL abstract values so that we can reverse map them correctly (i.e., not box them and not > map them to IDL, just as we do for non-abstract IDL values). I believe > the cleanest way to allow this is to make them inherit from ValueBase. This also allows IDL semantics to be supported correctly. The following text is in section 5.2.7: All value types have a conventional base type called ValueBase. This is a type which fulfills a role that is similar to that played by Object. Note that it says *all* value types, not all concrete value types. Therefore, it has to be possible to pass a Java interface representing an abstract value type through a signature of type ValueBase. BTW, for similar reasons it will be necessary to make ValueBase inherit from AbstractBase. See issue 2532. This inheritance needs to be specified as part of the 1980 proposal. > > Note that I did not ask for the current methods that take a ValueHelper > > to be retained. This is because if the above changes are made, ORB vendors > > can if they wish ship a compliant product that supports the ValueHelper > > mechanism without the need for additional APIs with ValueHelper signatures > > (deprecated or otherwise). > > > > All that needs to be done is to make the above changes and redefine > > ValueHelper as extending BoxedValueHelper (not unreasonable). Then the > > new register_value_factory and lookup_value_factory methods could take > > and return a ValueHelper, since ValueHelper is a subtype of ValueFactory. > > Also, the new stream read_value and write_value method overloads that take > > a BoxedValueHelper could be passed a ValueHelper, since ValueHelper is a > > subtype of BoxedValueHelper. ORB vendors would not have to support the > > ValueHelper mechanism but there would be nothing to stop an ORB vendor > > who needs to provide a migration path from the current spec to the new > > spec from shipping a runtime that can handle the ValueHelper case as well > > as the new mechanisms. > > Given the new suggestion I made, all the above will still be possible, and an ORB > that wishes to could still support the ValueHelper mechanism without changes to > the APIs. > > Hope this satisifies your concern. > Unfortunately, it doesn't, because of the problem with value helpers having to provide an implementation for create_for_unmarshal(). Simon -- Simon C Nash, Technology Architect, IBM Java Technology Centre Tel. +44-1962-815156 Fax +44-1962-818999 Hursley, England Internet: nash@hursley.ibm.com Lotus Notes: Simon Nash@ibmgb Date: Thu, 18 Mar 1999 08:30:49 -0800 From: "Vijaykumar Natarajan" X-Accept-Language: en To: Simon Nash CC: Vijaykumar Natarajan , George Scott , Jeff Mischkinsky , java-rtf@omg.org Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> <36F0BE7B.85403518@inprise.com> <36F0D926.23C69241@hursley.ibm.com> Hi Simon, > This does not work, because it requires the generated value helpers to have > an implementation for create_for_unmarshal(). Well, you are correct, but that could be a null implementation, and that IMHO is a minor cost to pay to support backward compatibility to a broken API. > > > > This would still achieve the ability to use the orb value factory registering > > APIs and the > > stream's read_value which takes the BoxedValueHelper. > > > > Also, note that what we proposed in java for create_for_unmarshal is identical to > > the C++ mapping. > > > Except that it's private in C++ and public in Java!! > > > > 2. Change BoxedValueHelper to be > > > public interface BoxedValueHelper extends ValueFactory { > > > void write_value(OutputStream os. java.io.Serializable value); > > > java.lang.String get_id(); > > > } > > > These two changes unify the creation and demarshalling of boxed values > > > and regular values with the same read_value(InputStream) method being > > > called in both cases. They also solve the safety problem that the > > > current create_for_unmarshal creates. > > > > > 3. Remove the public getValueFactory method on the value helper class. > > > This is not needed, since ORB.lookup_value_factory can easily be used > > > with little if any loss of convenience. This saves code in value helpers. > > > > OK! > > > > > 4. Change the name of the generated factory interface from xxValueFactory > > > to xxFactory. The proposal is currently inconsistent on this point. > > > > > > 5. Add a method > > > void read_value(java.io.Serializable value) { ... } > > > to InputStream, and show the read_value code in the helper calling > > > this method. > > > > > > 6. Remove the statement that the ValueHandler is used when an RMI: > > > repository ID is received. The ValueHandler must only be called > > > for non-IDLEntity types. Just because the repid is RMI: does not > > > mean that the class to be demarshalled is not an IDLEntity. > > > > You are correct. Can you suggest better words? > > > > > 7. Add SerializableHolder to allow ValueBase to be used as an out or > > > inout parameter. > > > > Yup, gotta have that! > > > > > 8. The proposal needs to say whether abstract value types extend ValueBase > > > or IDLEntity. It currently says neither. > > > > That is correct. This is to ensure that there is no direct implementation of the > > abstract value type interface > > that masquerades as an idl entity. All instances will be instances of a concrete > > value type which will implement the IDLEntity interface. > > > This is a serious issue for the reverse mapping. We need to be able to > detect Java interface types that were mapped from IDL abstract values > so that we can reverse map them correctly (i.e., not box them and not map > them to IDL, just as we do for non-abstract IDL values). I believe the > cleanest way to allow this is to make them inherit from ValueBase. > > This also allows IDL semantics to be supported correctly. The following > text is in section 5.2.7: > > All value types have a conventional base type called ValueBase. This is > a type which fulfills a role that is similar to that played by Object. > > Note that it says *all* value types, not all concrete value types. > Therefore, it has to be possible to pass a Java interface representing > an abstract value type through a signature of type ValueBase. > > BTW, for similar reasons it will be necessary to make ValueBase > inherit from AbstractBase. See issue 2532. This inheritance needs to > be specified as part of the 1980 proposal. Note that all valuetype instances will be of type IDL Entity and ValueBase. However, I do agree that the reverse mapping may need something to detect the difference, I accept to the addition of IDLEntity, but not the others. Vijay Date: Thu, 18 Mar 1999 16:04:45 +0000 From: Simon Nash Organization: IBM To: Vijaykumar Natarajan CC: George Scott , Jeff Mischkinsky , java-rtf@omg.org Subject: Re: Issue 1980 - Proposed amendments References: <36F06361.4262A406@hursley.ibm.com> <36F0BE7B.85403518@inprise.com> <36F0D926.23C69241@hursley.ibm.com> <36F12A39.258F4E12@inprise.com> Vijay, Vijaykumar Natarajan wrote: > > Hi Simon, > > > This does not work, because it requires the generated value > helpers to have > > an implementation for create_for_unmarshal(). > > Well, you are correct, but that could be a null implementation, and > that IMHO is a > minor cost > to pay to support backward compatibility to a broken API. > Well IMHO there are two better options on the table that to do not require us to put in a kludge like this. How would we describe this method in our documentation? > > > > > This would still achieve the ability to use the orb value > factory registering > > > APIs and the > > > stream's read_value which takes the BoxedValueHelper. > > > > > > Also, note that what we proposed in java for > create_for_unmarshal is identical to > > > the C++ mapping. > > > > > Except that it's private in C++ and public in Java!! > > > > > > 2. Change BoxedValueHelper to be > > > > public interface BoxedValueHelper extends ValueFactory { > > > > void write_value(OutputStream > os. java.io.Serializable value); > > > > java.lang.String get_id(); > > > > } > > > > These two changes unify the creation and demarshalling of > boxed values > > > > and regular values with the same read_value(InputStream) > method being > > > > called in both cases. They also solve the safety problem > that the > > > > current create_for_unmarshal creates. > > > > > > > 3. Remove the public getValueFactory method on the value > helper class. > > > > This is not needed, since ORB.lookup_value_factory can > easily be used > > > > with little if any loss of convenience. This saves code in > value helpers. > > > > > > OK! > > > > > > > 4. Change the name of the generated factory interface from > xxValueFactory > > > > to xxFactory. The proposal is currently inconsistent on > this point. > > > > > > > > 5. Add a method > > > > void read_value(java.io.Serializable value) { ... } > > > > to InputStream, and show the read_value code in the helper > calling > > > > this method. > > > > > > > > 6. Remove the statement that the ValueHandler is used when an > RMI: > > > > repository ID is received. The ValueHandler must only be > called > > > > for non-IDLEntity types. Just because the repid is RMI: > does not > > > > mean that the class to be demarshalled is not an IDLEntity. > > > > > > You are correct. Can you suggest better words? > > > > > > > 7. Add SerializableHolder to allow ValueBase to be used as an > out or > > > > inout parameter. > > > > > > Yup, gotta have that! > > > > > > > 8. The proposal needs to say whether abstract value types > extend ValueBase > > > > or IDLEntity. It currently says neither. > > > > > > That is correct. This is to ensure that there is no direct > implementation of the > > > abstract value type interface > > > that masquerades as an idl entity. All instances will be > instances of a concrete > > > value type which will implement the IDLEntity interface. > > > > > This is a serious issue for the reverse mapping. We need to be > able to > > detect Java interface types that were mapped from IDL abstract > values > > so that we can reverse map them correctly (i.e., not box them and > not map > > them to IDL, just as we do for non-abstract IDL values). I > believe the > > cleanest way to allow this is to make them inherit from ValueBase. > > > > This also allows IDL semantics to be supported correctly. The > following > > text is in section 5.2.7: > > > > All value types have a conventional base type called > ValueBase. This is > > a type which fulfills a role that is similar to that played by > Object. > > > > Note that it says *all* value types, not all concrete value types. > > Therefore, it has to be possible to pass a Java interface > representing > > an abstract value type through a signature of type ValueBase. > > > > BTW, for similar reasons it will be necessary to make ValueBase > > inherit from AbstractBase. See issue 2532. This inheritance > needs to > > be specified as part of the 1980 proposal. > > Note that all valuetype instances will be of type IDL Entity and > ValueBase. However, I > do agree > that the reverse mapping may need something to detect the > difference, I accept to the > addition of > IDLEntity, but not the others. > This needs to be on the declared type, not just on the runtime > instance. Otherwise the rmic compiler will not be able to generate correct IDL. It will attempt to generate a boxed IDLEntity which is wrong. Simon -- Simon C Nash, Technology Architect, IBM Java Technology Centre Tel. +44-1962-815156 Fax +44-1962-818999 Hursley, England Internet: nash@hursley.ibm.com Lotus Notes: Simon Nash@ibmgb Date: Thu, 18 Mar 1999 11:57:22 -0800 From: David Heisser Organization: Sun Microsystems Inc. X-Accept-Language: en To: Jeffrey Mischkinsky CC: java-rtf@omg.org Subject: Re: Java 2.4 Current Vote Status References: <199903180348.TAA21936@wheel.dcn.davis.ca.us> Sun votes NO on Vote 5 issue 1980. This supercedes the verbal vote I gave Jeff yesterday 3/17. A compromise proposal was reached today which Sun will support when it is included in the vote. dh Jeffrey Mischkinsky wrote: > Hi, > > Vote 1 closed a while ago, with all issues passing. > > These are the officially recorded votes: > > Vote 2 close today - passed - 4-0-0-1 Y(IBM, Ioona, Inprise, Sun), NV(HP)? > Vote 3 closed today - passed - 3-0-2 Y(IBM, Inp, HP), A(Iona, Sun) > Vote 4 closes tomorrow - currently 3-0-0-2 Y(IBM, Inprise, Sun), NV(Iona, HP) > Vote 5 closes tomorrow - currently 2-0-0-3 Y(Inprise, Sun), NV(Iona, HP, IBM) > > jeff > > Mary, I just searched both my mail servers and couldn't find a message from > you for Vote 2. Did I accidentally delete it or move it a strange > place? > > -- > Jeff Mischkinsky > jmischki@dcn.davis.ca.us +1 530-758-9850 > jeffm@inprise.com +1 650-358-3049 Date: Sat, 18 Dec 1999 19:02:25 +0000 From: Simon Nash Organization: IBM X-Mailer: Mozilla 4.5 [en] (Win98; I) X-Accept-Language: en MIME-Version: 1.0 To: issues@omg.org CC: java-rtf@omg.org Subject: Factories for boxed valuetypes Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: l0=e9o'fd9]4b!!#$8e9 There has been recent discussion on the orb_revision mailing list about whether boxed valuetypes have value factories. The Java mapping for valuetypes that was agreed by the RTF (issue 1980) states clearly that there are no factories for boxed valuetypes, but this is not stated explicitly in the published spec. Proposed resolution: Add the following text from the adopted resolution to issue 1980 to the published IDL to Java mapping spec. Since this text was already approved by an RTF vote, adding it to the spec is editorial and does not require a further RTF vote. A boxed value needs to be treated differently than regular values in Java. Boxed values don't have factories and don't implmenent either the StreamableValue or CustomValue interfaces, so their marshalling and unmarshalling is performed by a boxed value helper object. In all cases, code can be generated to unmarshal the boxed type. No user code is required for boxed values. The BoxedValueHelper interface is implemented by all generated Helper classes for boxed valuetypes. The inherited read_value() method is called by the ORB runtime in the process of unmarshalling a boxed valuetype. This is required for types that are immutable either in content (eg, string), or size (eg, sequences). The write_value() method call is used for marshalling the value box. Also add the example for BoxedString from the 1980 resolution which includes a generated helper class which unmarshals boxed strings without a value factory, as follows: public final class BoxedStringHelper implements org.omg.CORBA.portable.BoxedValueHelper { private static final BoxedStringHelper _instance = new BoxedStringHelper(); public static java.lang.String read (final org.omg.CORBA.portable.InputStream _input) { if (!(_input instanceof org.omg.CORBA_2_3.portable.InputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } return (java.lang.String)((org.omg.CORBA_2_3.portable.InputStream)_input).read_value(_instance); } public static void write (final org.omg.CORBA.portable.OutputStream _output, final java.lang.String value) { if (!(_output instanceof org.omg.CORBA_2_3.portable.OutputStream)) { throw new org.omg.CORBA.BAD_PARAM(); } ((org.omg.CORBA_2_3.portable.OutputStream)_output).write_value(value, _instance); } public static void insert (org.omg.CORBA.Any any, java.lang.String value) {...} public static java.lang.String extract (org.omg.CORBA.Any any) {...} public static org.omg.CORBA.TypeCode type () {...} public static java.lang.String id () {...} public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream _input) { java.lang.String result; result = _input.read_string(); return (java.io.Serializable)result; } public void write_value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable value) { if (!(value instanceof java.lang.String)) { throw new org.omg.CORBA.MARSHAL(); } java.lang.String valueType = (java.lang.String)value; _output.write_string(valueType); } public java.lang.String get_id () { return id(); } } Simon -- Simon C Nash, Technology Architect, IBM Java Technology Centre Tel. +44-1962-815156 Fax +44-1962-818999 Hursley, England Internet: nash@hursley.ibm.com Lotus Notes: Simon Nash@ibmgb