Issue 2514: PortableServer Servant issue (java-rtf) Source: (, ) Nature: Uncategorized Issue Severity: Summary: Summary: The currently specified definition of the org.omg.CORBA.PortableServer.Servant class does not correctly implement the behavior specified. In particular, the POA returned by PortableServer::Current::get_POA is always used during the processing of _this_object() even if _this_object() is not being called on the Servant which is currently being invoked as part of the request. This contradicts the behavior defined in the first bullet item for _this_object as defined in section 25.19.2.1 "Mapping of PortableServer::Servant". Also, the overall behavior of _this() may need some tweaking (see my other email "Behavior of POA Servant"s _this()"), which may require us to revisit the definition of the Servant class. Resolution: resolved, see revised text Revised Text: The current definition of org.omg.PortableServer.Servant does not correctly implement the specification defined for Servant as defined by the Java mapping. In particular, it does not correctly implement the semantics of bullet item number one defined for _this_object(). Furthermore, the current definition of Servant hard codes certain functionality and prevents vendors from making fixes or otherwise changing the implementation. To fix this problem, a delegation model for the Servant class similar to that used by stubs is proposed in order to allow vendors full control over the way that certain Servant operations are handled. We believe this is necessary to correctly implement the _this_object() method for which a correct implementation using the currently defined public POA APIs is somewhat problematic. The proposal also allows vendors flexibility in the implementation of the methods way which may allow for better optimization opporutunities. The proposed changes have minimum impact on end user applications as well as minimal impact on ORB vendors (the Visibroker ORB was converted to the new design in less than a day including time to implement _this_object()). The only API change end users will see is the removal of the method: void _orb(org.omg.CORBA.ORB orb); This method does not work well with the new delegation model, and it has been our experience that this method is rarely, if ever, used. The only need a user ever has to set the ORB on a Servant is for the case of implicit activation, and the prefered way is to use the method: org.omg.CORBA.Object _this_object(org.omg.CORBA.ORB orb); The _this_object() method is still provided, but now sets the delegate instead of setting a locally stored ORB variable. We believe this method is required and also commonly used so should remain part of the user API. The proposal defines a new Delegate interface which is defined in a new package org.omg.PortableServer.portable and mirrors the design pattern used by the Stub classes for the Java mapping. Unlike stubs, however, the Servant must have a way of setting its delegate given an instance of the ORB in order to support implicit activation via _this(). To accomplish this our proposal includes the addition of a new method on the ORB class: public void set_delegate(java.lang.Object object); This method will actually appear on org.omg.CORBA_2_3.ORB due to the org.omg.CORBA.ORB class being frozen in the Java 2 core. This method takes an object which is known to the ORB to follow the delegation model and sets it delegate. In this version of the proposal the only type that an ORB is required to support setting the delegate is org.omg.PortableServer.Servant. However, we expect in the future it may be possible to make use of this method to set delegates on stubs which have been reincarnated through Java serialization. Note, we also chose to make the Delegate an interface rather than an abstract class to provide for greater flexibility in the implementation. This proposal as it fixes an important piece of POA functionality and is required for correct operation of the POA. George Scott, gscott@inprise.com Revised Text: In Section 25.19.10 "ORB". Add the following new method to org.omg.CORBA_2_3.ORB: public abstract class ORB extends org.omg.CORBA.ORB { abstract public void set_delegate(java.lang.Object wrapper); } Add the following paragraph following the class definition for org.omg.CORBA_2_3.ORB: Add a new section: 25.19.10.1 set_delegate at the end of section 25.19.10 "The set_delegate() method supports the Java ORB portability interfaces by providing a method for classes which support ORB portability through delegation to set their delegate. This is typically required in cases where instances of such classes were created by the application programmer rather than the ORB runtime. The wrapper parameter is the instance of the object on which the ORB must set the delegate. The mechanism to set the delegate is specific to the class of the wrapper instance. The set_delegate() method shall support setting delegates on instances of the following Java classes: - org.omg.PortableServer.Servant If the wrapper paramter is not an instance of a class for which the ORB can set the delegate, the CORBA::BAD_PARAM exception shall be thrown." In Section 25.20.2.1 "Mapping of PortableServer::Servant", reformat the methods and group them to clarify their use as follows: Add the comment below and group the following 5 methods // Convenience methods for application programmer final public org.omg.CORBA.Object _this_object() {...} final public org.omg.CORBA.Object _this_object(ORB orb) {...} final public org.omg.CORBA.ORB _orb() {...} final public POA _poa() {...} final public byte[] _object_id() {...} Add the comment below and group the following 4 methods: // Methods which may be overriden by the application programmer public POA _default_POA() {...} public boolean _is_a(String repository_id) {...} public boolean _non_existent() {...} public org.omg.CORBA.InterfaceDef _get_interface() {...} Add the comment below and group the following 1 methods: // Methods for which the skeleton or application programmer must // provide an implementation abstract public String[] _all_interfaces(POA poa, byte[] objectId); Delete the following method: final public void _orb(ORB orb) {...} Replace the following paragraph which reads as "The Servant class is an abstract Java class which serves as the base classfor all POA Servant implementations." with the following 3 paragraphs: "The Servant class is an abstract Java class which serves as the base classfor all POA Servant implementations. It provides a number of methods which may be invoked by the application programmer, as well as methods which are invoked by the POA itself and may be overridden by the user to control aspects of Servant behavior. With the exception of the _all_interfaces() and _this_object(ORB orb) methods, all methods defined on the Servant class may only be invoked after the Servant has been associated with an ORB instance. Attempting to invoke the methods on a Servant which has not been associated with an ORB instance shall result in a CORBA::BAD_INV_ORDER exception being raised. A Servant is associated with an ORB instance via one of the following means: 1. Through a call to _this_object(ORB orb) passing an ORB instance as parameter. The Servant will become associated with the specified ORB instance. 2. By explicitly activating a Servant with a POA by calling either POA::activate_object or POA::activate_object_with_id. Activating a Servant in this fashion will associate the Servant with the ORB instance which contains the POA on which the Servant has been activated. 3. By returning a Servant instance from a ServantManager. The Servant returned from PortableServer::ServantActivator::incarnate() or PortableServer::ServantLocator::preinvoke() will be associated with the ORB instance which contains the POA on which the ServantManager is installed. 4. By installing the Servant as a default servant on a POA. The Servant will become associated with the ORB instance which contains the POA for which the Servant is acting as a default servant. It is not possible to associate a Servant with more than one ORB instance at a time. Attempting to associate a Servant with more than one ORB instance will result in undefined behavior. Replace Section 25.20.2.1.2 _orb with: The _orb() method is a convenience method which returns the instance of the ORB which is currently associated with the Servant." In Section 25.20.2.1.1 _this_object Replace the fourth bullet item with the following text: " * The _this_object(ORB orb) method first associates the Servant with the specified ORB instance and then invokes _this_object() as normal." In Section 25.21.2 "Overall Architecture" Add the following bullet after the "Portable Delegate" bullet: " * Portable Servant Delegate - provides the vendor specific implementation of PortableServer::Servant" In Section 25.21.2.1 "Portability Package" Change the first sentence to the following: "The APIs needed to implement portability are found in the org.omg.CORBA.portable and org.omg.PortableServer.portable packages." Add the following new sections after section 25.21.6 "Delegate": (ORB becomes 25.21.9) " 25.21.7 "Servant" The Servant class is the base class for all POA-based implementations. It delegates all functionality to the Delegate interface defined in section 25.21.6. package org.omg.PortableServer; import org.omg.CORBA.ORB; import org.omg.PortableServer.portable.Delegate; abstract public class Servant { private transient Delegate _delegate = null; final public Delegate _get_delegate() { if (_delegate == null) { throw new org.omg.CORBA.BAD_INV_ORDER("The Servant has not been associated with an ORB instance"); } return _delegate; } final public void _set_delegate(Delegate delegate) { _delegate = delegate; } final public org.omg.CORBA.Object _this_object() { return _get_delegate().this_object(this); } final public org.omg.CORBA.Object _this_object(ORB orb) { try { ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this); } catch(ClassCastException e) { throw new org.omg.CORBA.BAD_PARAM("POA Servant requires an instance of org.omg.CORBA_2_3.ORB"); } return _this_object(); } // access to the ORB final public ORB _orb() { return _get_delegate().orb(this); } // convenience methods to the POA Current final public POA _poa() { return _get_delegate().poa(this); } final public byte[] _object_id() { return _get_delegate().object_id(this); } // Methods which may be overriden by the user public POA _default_POA() { return _get_delegate().default_POA(this); } public boolean _is_a(String repository_id) { return _get_delegate().is_a(this, repository_id); } public boolean _non_existent() { return _get_delegate().non_existent(this); } public org.omg.CORBA.InterfaceDef _get_interface() { return _get_delegate().get_interface(this); } // methods for which the user must provide an implementation abstract public String[] _all_interfaces(POA poa, byte[] objectId); } 25.21.8 "Servant Delegate" The Delegate interface provides the ORB vendor specific implementation of PortableServer::Servant. package org.omg.PortableServer.portable; import org.omg.PortableServer.Servant; import org.omg.PortableServer.POA; public interface Delegate { org.omg.CORBA.ORB orb(Servant self); org.omg.CORBA.Object this_object(Servant self); POA poa(Servant self); byte[] object_id(Servant self); POA default_POA(Servant self); boolean is_a(Servant self, String repository_id); boolean non_existent(Servant self); org.omg.CORBA.InterfaceDef get_interface(Servant self); } Rename Section 25.21.6 "Delegate" to "Stub Delegate". Actions taken: March 5, 1999: received issue June 4, 1999: closed issue Discussion: End of Annotations:===== Sender: "George Scott" Date: Thu, 04 Mar 1999 19:48:21 -0800 From: "George M. Scott" Organization: Inprise Corporation X-Accept-Language: en To: java-rtf@omg.org Subject: PortableServer Servant issue The currently specified definition of the org.omg.CORBA.PortableServer.Servant class does not correctly implement the behavior specified. In particular, the POA returned by PortableServer::Current::get_POA is always used during the processing of _this_object() even if _this_object() is not being called on the Servant which is currently being invoked as part of the request. This contradicts the behavior defined in the first bullet item for _this_object as defined in section 25.19.2.1 "Mapping of PortableServer::Servant". Also, the overall behavior of _this() may need some tweaking (see my other email "Behavior of POA Servant's _this()"), which may require us to revisit the definition of the Servant class. George Date: Fri, 12 Mar 1999 14:28:06 -0800 From: "George Scott" Organization: Inprise Corporation X-Accept-Language: en To: java-rtf@omg.org CC: gscott@inprise.com, jeffm@inprise.com Subject: Proposal for Issue 2514: Java POA Servant The current definition of org.omg.PortableServer.Servant does not correctly implement the specification defined for Servant as defined by the Java mapping. In particular, it does not correctly implement the semantics of bullet item number one defined for _this_object(). Furthermore, the current definition of Servant hard codes certain functionality and prevents vendors from making fixes or otherwise changing the implementation. To fix this problem, we are proposing a delegation model for the Servant class similar to that used by stubs to allow vendors full control over the way that certain Servant operations are handled. We believe this is necessary to correctly implement the _this_object() method which cannot be correctly implemented using public POA APIs at this time. It also allows vendors flexibility to implement the methods in a way which may be more optimized for their implementation. The proposed changes have minimum impact on end user applications as well as minimal impact on ORB vendors (our ORB was converted to the new design in less than a day including time to correctly implement _this_object()). The only API change end users will see is the removal of the method: void _orb(org.omg.CORBA.ORB orb); This method does not work well with the new delegation model, and it has been our experience that this method is rarely, if ever, used. The only need a user ever has to set the ORB on a Servant is for the case of implicit activation, and the prefered way is to use the method: org.omg.CORBA.Object _this_object(org.omg.CORBA.ORB orb); This method is still provided, but now sets the delegate instead of setting a locally stored ORB variable. We believe this method is required and also commonly used so should remain part of the user API. The proposal defines a new Delegate interface which is defined in a new package org.omg.PortableServer.portable and mirrors the design pattern used by the Stub classes for the Java mapping. Unlike stubs, however, the Servant must have a way of setting its delegate given an instance of the ORB in order to support implicit activation via _this(). To accomplish this our proposal includes the addition of a new method on the ORB class: public void set_delegate(java.lang.Object object); This method will actually appear on org.omg.CORBA_2_3.ORB due to the org.omg.CORBA.ORB class being frozen in the Java 2 core. This method takes an object which is known to the ORB to follow the delegation model and sets it delegate. In this version of the proposal the only type that an ORB is required to support setting the delegate is org.omg.PortableServer.Servant. However, we expect in the future to make use of this method to set delegates on stubs which have been reincarnated through Java serialization (given the time left on the current RTF we do not believe there is time to add such a feature to the language mapping without some implementation experience). Note, we also chose to make the Delegate an interface rather than an abstract class to provide for greater flexibility in the implementation. The complete proposal is below including all changes to the Java language mapping chapter. We would like to call for a vote on this proposal as it fixes an important piece of POA functionality and is required for correct operation of the POA. George Proposal ======== In Section 25.18.11 "ORB". Add new abstract class (should already be added by OBV/Java proposal) org.omg.CORBA_2_3.ORB which contains the following method definition: package org.omg.CORBA_2_3; public abstract class ORB extends org.omg.CORBA.ORB { abstract public void set_delegate(java.lang.Object wrapper); } Add the following paragraph following the class definition for org.omg.CORBA_2_3.ORB: "The set_delegate() method supports the Java ORB portability interfaces by allowing classes which support ORB portability through delegation to set their delegate. This is typically required in cases where instances of such classes were created by the application programmer rather than the ORB runtime. The wrapper parameter is the instance of the object on which the ORB must set the delegate. The mechanism to set the delegate is specific to the class of the wrapper instance. The set_delegate() method must support setting delegates on instances of the following Java classes: - org.omg.PortableServer.Servant If the wrapper paramter is not an instance of a class for which the ORB can set the delegate, the CORBA::BAD_PARAM exception is thrown." In Section 25.19.2.1 "Mapping of PortableServer::Servant" replace the first three paragaphs (including code for Servant) with the following: "The PortableServer module for the Portable Object Adapter (POA) defines the native Servant type. In Java, the Servant is mapped to the Java org.omg.PortableServer.Servant class. The class is fully specified in Section 25.20.xx "Servant". The application programmer interfaces to the class are defined below. // Java package org.omg.PortableServer; import org.omg.CORBA.ORB; abstract public class Servant { // other methods to support ORB portability // ... // Convenience methods for application programmer final public org.omg.CORBA.Object _this_object() {...} final public org.omg.CORBA.Object _this_object(ORB orb) {...} final public org.omg.CORBA.ORB _orb() {...} final public POA _poa() {...} final public byte[] _object_id() {...} // Methods which may be overriden by the application programmer public POA _default_POA() {...} public boolean _is_a(String repository_id) {...} public boolean _non_existent() {...} public org.omg.CORBA.InterfaceDef _get_interface() {...} // Methods for which the skeleton or application programmer must // provide an implementation abstract public String[] _all_interfaces(POA poa, byte[] objectId); } The Servant class is an abstract Java class which serves as the base class for all POA Servant implementations. It provides a number of methods which may be invoked by the application programmer, as well as methods which are invoked by the POA itself and may be overridden by the user to control aspects of Servant behavior. With the exception of the _all_interfaces() and _this_object(ORB orb) methods, all methods defined on the Servant class may only be invoked after the Servant has been associated with an ORB instance. Attempting to invoke the methods on a Servant which has not been associated with an ORB instance will result in a CORBA::BAD_INV_ORDER exception being raised. A Servant is associated with an ORB instance via one of the following means: 1. Through a call to _this_object(ORB orb) passing an ORB instance as parameter. The Servant will become associated with the specified ORB instance. 2. By explicitly activating a Servant with a POA by calling either POA::activate_object or POA::activate_object_with_id. Activating a Servant in this fashion will associate the Servant with the ORB instance which contains the POA on which the Servant has been activated. 3. By returning a Servant instance from a ServantManager. The Servant returned from PortableServer::ServantActivator::incarnate or PortableServer::ServantLocator::preinvoke will be associated with the ORB instance which contains the POA on which the ServantManager is installed. 4. By installing the Servant as a default servant on a POA. The Servant will become associated with the ORB instance which contains the POA for which the Servant is acting as a default servant. It is not possible to associate a Servant with more than one ORB instance at a time. Attempting to associate a Servant with more than one ORB instance will result in undefined behavior. The _orb() method is a convenience method which returns the instance of the ORB which is currently associated with the Servant." On the definition of _this_object() in the same section. Replace the fourth bullet item with the following text: " * The _this_object(ORB orb) method first associates the Servant with the specified ORB instance and then invokes _this_object() as normal." In Section 25.20.2 "Overall Architecture" Add the following bullet after the "Portable Delegate" bullet: " * Portable Servant Delegate - provides the vendor specific implementation of PortableServer::Servant" In Section 25.20.2.1 "Portability Package" Change the first sentence to the following: "The APIs needed to implement the portability are found in the org.omg.CORBA.portable and org.omg.PortableServer.portable packages." Add the following new sections after section 25.20.6 "Delegate": " 25.20.xx "Servant" The Servant class is the base class for all POA-based implementations. It delegates all functionality to the Delegate interface defined in section 25.20.xx. package org.omg.PortableServer; import org.omg.CORBA.ORB; import org.omg.PortableServer.portable.Delegate; abstract public class Servant { private transient Delegate _delegate = null; final public Delegate _get_delegate() { if (_delegate == null) { throw new org.omg.CORBA.BAD_INV_ORDER("The Servant has not been associated with an ORB instance"); } return _delegate; } final public void _set_delegate(Delegate delegate) { _delegate = delegate; } final public org.omg.CORBA.Object _this_object() { return _get_delegate().this_object(this); } final public org.omg.CORBA.Object _this_object(ORB orb) { try { ((org.omg.CORBA_2_3.ORB)orb).set_delegate(this); } catch(ClassCastException e) { throw new org.omg.CORBA.BAD_PARAM("POA Servant requires an instance of org.omg.CORBA_2_3.ORB"); } return _this_object(); } // access to the ORB final public ORB _orb() { return _get_delegate().orb(this); } // convenience methods to the POA Current final public POA _poa() { return _get_delegate().poa(this); } final public byte[] _object_id() { return _get_delegate().object_id(this); } // Methods which may be overriden by the user public POA _default_POA() { return _get_delegate().default_POA(this); } public boolean _is_a(String repository_id) { return _get_delegate().is_a(this, repository_id); } public boolean _non_existent() { return _get_delegate().non_existent(this); } public org.omg.CORBA.InterfaceDef _get_interface() { return _get_delegate().get_interface(this); } // methods for which the user must provide an implementation abstract public String[] _all_interfaces(POA poa, byte[] objectId); } 25.20.xx "Servant Delegate" The Delegate interface provides the ORB vendor specific implementation of PortableServer::Servant. package org.omg.PortableServer.portable; import org.omg.PortableServer.Servant; import org.omg.PortableServer.POA; public interface Delegate { org.omg.CORBA.ORB orb(Servant self); org.omg.CORBA.Object this_object(Servant self); POA poa(Servant self); byte[] object_id(Servant self); POA default_POA(Servant self); boolean is_a(Servant self, String repository_id); boolean non_existent(Servant self); org.omg.CORBA.InterfaceDef get_interface(Servant self); } " Rename Section 25.20.6 "Delegate" to "Stub Delegate".