Issue 3392: OCL needs an abstract syntax, just like the UML metamode (ocl2-ftf) Source: OpenModeling (Mr. Jos Warmer, jos.warmer(at)openmodeling.nl) Nature: Uncategorized Issue Severity: Summary: OCL needs an abstract syntax, just like the UML metamodel. This will clarify many issues about the exact semantics of OCL. This request has been made by multiple sources. Resolution: Revised Text: Resolution: This is an OCL 1 issue transferred to the OCL 2 FTF. Section 8 of the OCL2 specification provides the metamodel. Revised text: No text change needed. Actions taken: March 1, 2000: received issue December 2, 2004: Transferred to OCL 2.0 FTF November 1, 2005: closed issue Discussion: End of Annotations:===== From: "George M. Scott" Organization: Inprise Corporation To: obv-rtf@omg.org, java-rtf@omg.org Subject: OBV Java mapping changes We have discovered a few issues with the OBV Java language mapping, which need to be addressed. We have outlined the issues below, followed by the proposed solutions. As with my previous posts, these are not currently formal proposals, just working drafts. ;-) Note, we are in the process of reviewing Bernard's proposed OBV/Java changes as well, and will comment on those soon with respect to this proposal. Here are the current issues: 3. Java valuetypes need a way to unmarshal the state of their base class. Here is our complete proposal: 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(); 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: abstract class AValueBase implements org.omg.CORBA.portable.IDLEntity { public int l; protected short s; abstract void foo(); } The user would have to provide a concrete class which matched the name of the specified valutype, in this case "A", which extends the abstract ValueBase class. An IDL compiler, could of course, generate a "sample" implementation. The user defined class must contain a static method named for create_for_unmarshal which returns an instance of the class which can be used for unmarshalling. This static method is called by the ValueHelper method create_for_unmarshal, when the ORB runtime calls for create_for_unmarshal on the ValueHelper. For example the following is a valid implementation of A: public class A extends AValueBase { public A(int l) { ... } public void foo() { ... } public static A create_for_unmarshal() { ... } } The Helper classes are also augmented with the following additional methods: public static void read_base(org.omg.CORBA.portable.InputStream is, value); public static void write_base(org.omg.CORBA.portable.OutputStream os, value); These two methods are intended to be called by the Helper's read_Value and write_Value methods to marshal the state of the type's base class. The following example illustrates the use of the various read/write methods on value Helpers (note this code is not perfect, for example it does not check to see if casts may fail.). // IDL valuetype A { public long l; }; valuetype B : A { public short s; }; // Java public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... public java.io.Serializable create_for_unmarshal () { return A.create_for_unmarshal(); } public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable obj) { read_base(_input, (A) obj); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable obj) { write_base(_output, (A) obj); } 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 static void read_base(org.omg.CORBA.portable.InputStream _input, A value) { value.l = _input.read_long(); } public static void write_base(org.omg.CORBA.portable.OutputStream _output, A value) { _output.write_long(value.l); } } public class BHelper implements org.omg.CORBA.portable.ValueHelper { ... public java.io.Serializable create_for_unmarshal () { return B.create_for_unmarshal(); } public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable obj) { read_base(_input, (B) obj); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable obj) { write_base(_output, (B) obj); } 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()); } public static void read_base(org.omg.CORBA.portable.InputStream _input, B value) { AHelper.read_base(_input, value); value.s = _input.read_short(); } public static void write_base(org.omg.CORBA.portable.OutputStream _output, B value) { AHelper.write_base(_output, value); _output.write_short(value.s); } } Our proposal addressed our five 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. Additional methods have been added to value Helper classes which allow a subclass to marshal the base class state. 4. The Helper interface has been removed to reduce the overall space requirement for the mapping. 5. get_safe_base_ids has been renamed get_truncatable_ids. George Return-Path: Date: Wed, 02 Sep 1998 11:58:29 +0100 From: Simon Nash Reply-To: nash@hursley.ibm.com Organization: IBM To: "George M. Scott" Cc: obv-rtf@omg.org, java-rtf@omg.org Subject: Re: OBV Java mapping changes References: <35ECCC52.12AF79B4@inprise.com> George, In general I am OK with this but there are two issues that concern me. 1. In the previous mapping, the IDL compiler generated constructors for each IDL initializer. In your proposal, this is the responsibility of the Java implementer. This is burdensome and error-prone, as the implementer needs to manually map parameter types on IDL initializers when coding the constructors. There is no compile-time check that this was done correctly, unlike regular methods where the abstract declarations in the base class provide this check. Although a tool could provide a correct initial template, this does not cover evolution of the IDL definition and keeping the implementation in sync. My proposal to correct this is to use an approach similar to that of the OBV C++ mapping. The generated base class would contain overloaded static create methods for the IDL initializers. These would create an uninitialized object and then call an overloaded _init method which would be declared as abstract in the base class. The implementer of the value type would implement the _init methods in the concrete implementation subclass. Since this approach no longer requires IDL initializers to be mapped to overloaded constructors, we could retain the current approach of creating implementation objects using a package-private no-argument constructor (default constructor) on the value implementation. This would allow us to eliminate the proposed create_for_unmarshal static method on the value implementation, which further simplifies the task of the value implementer. Here's an example of how this would look: // 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); public static A create(int l) { A newA = (A) new _AImpl(); newA._init(l); return newA; } } The user would have to provide a package-private concrete implementation class named _Impl, where is the name of the specified value type, in this case "A", which extends the abstract base class. An IDL compiler could, of course, generate a "sample" implementation. There is no need for any constructors in the implementation class as the default package-private no-argument constructor is suitable for use by the create methods and 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() { ... } } The generated helper class contains the following code: public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... public java.io.Serializable create_for_unmarshal () { return new _AImpl(); } } 2. The proposed read_base and write_base methods aren't needed. The read_Value and write_Value methods can be used instead, as follows: public class AHelper implements org.omg.CORBA.portable.ValueHelper { ... 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); } } public class BHelper extends AHelper { ... public void read_Value (org.omg.CORBA.portable.InputStream _input, java.io.Serializable obj) { super(_input, obj); ((B) obj).s = _input.read_short(); } public void write_Value (org.omg.CORBA.portable.OutputStream _output, java.io.Serializable obj) { super(_output, obj); _output.write_short(((B) obj).s); } } 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