Issue 4701: Colocated calls in Java (java-rtf) Source: Oracle (Mr. Ken Cavanaugh, nobody) Nature: Uncategorized Issue Severity: Summary: Note: this is NOT issue 3754, but it is related. A new issue is needed as described below: -------------------------------------------------------------------------- Issue 3754 (colocated call optimization and portable interceptors) was raised some time ago by Harold Carr. This issue discusses the problems of supporting portable interceptors for RMI-IIOP calls when the colocated call optimization is used. The basic issue is that there is no way for the ORB to detect whether a local dispatch to a servant completed normally or completed by throwing an exception. This problem exists because the current is_local/servant_preinvoke/servant_postinvoke mechanism has no way to report normal or exceptional completion of a local dispatch. The same problem arises in the IDL stub case as well. Both Java mappings can share the same solution here, but a solution requires changing part of the portable stub API which is shared by both mappings. In the discussion of 3754, Simon Nash asked to reassign the issue from the Java to IDL RTF to the Java mapping RTF. We really need two separate issues here. I propose that we do the following: 1. Move 3754 back to the Java to IDL RTF since Harold wrote the issue with the RMI-IIOP mapping in mind. 2. Create a new Java mapping issue for the same problem. The bulk of this message should be the new issue. Both RTFs will need to consider the issues. The new Java mapping issue will need to propose extensions to the portable stub APIs and document the required changes in the IDL based stubs, while the resolution to 3754 will need to adopt the same new portable stub API and document the required changes in the RMI-IIOP stubs. To start a discussion, here is my initial proposal for solving this problem in the Java mapping RTF: We need to add methods to report the result of the local dispatch. I propose that we extend the portable definition of ServantObject as follows: abstract public class ServantObjectExt extends ServantObject { abstract public void normalCompletion() ; abstract public void exceptionalCompletion( Throwable thr ) ; } Another alternative is to extend the Delegate class instead. I prefer the ServantObject approach because the method signatures are simpler: adding these methods on the Delegate would require passing ServantObject as an argument, since multiple threads could be simultaneously invoking methods on the same object reference, which would share the same delegate. Making this change makes it necessary to consider what happens in mixed versions. Old stub, Old ServantObject: no change New stub, new ServantObject: stub always invokes either normalCompletion or exceptionalCompletion, so the ORB has enough information to correctly implement portable interceptor behavior. Note that a location forward (e.g. from a ServantManager) is not a problem today, since it happens inside of _servant_preinvoke, which allows the ORB to correctly handle that case. New stub, old ServantObject: If a new stub is written to do an instanceof check on the ServantObject it gets from _servant_preinvoke, it can correctly determine whether or not to call the new methods. There are a number of possibilities for the check: 1. Just use (so instanceof ServantObjectExt) and rely on the ServantObjectExt class to be defined somewhere in the environment. New stubs that wanted to be compatible with old ORBs would need to be packaged somehow with this class in their classpath. The stubs would need the ServantObjectExt class both at compile time and at runtime. 2. A stub could be written to entirely use reflection for the instanceof check and the method invocation. This would avoid the requirement to have ServantObjectExt in the classpath, but would require more code in the stubs, plus run a little slower (probably about 2X slower in JDK 1.4, but in earlier JDKs the penalty could easily be 10-20X). Old stub, new ServantObject: In this case, neither method is ever invoked, so the ORB can tell the difference between normal completion and an old stub. The PI implementation in this case is free to do anything. However, probably the best approach is to extend RequestInfo::reply_status with a new value PortableInterceptor::UNKNOWN. Then the local case would always use the interceptor points send_other and receive_other with a reply_status set to UNKNOWN. This extension requires a new core issue. It is worth noting here that the PI change makes it reasonable to consider simply changing PI, and avoid changing the ServantObject API and 2 language mappings. In this case, a user of PI cannot tell what is happening with colocated calls in a very basic sense: did the operation complete successfully or not? Many applications of PI (for example, transactions and security) often do not require the use of PI in the colocated case. However, one important application is best done this way: logging/tracing in a complex system. I believe this argues strongly for extending the mapping, since a log entry that cannot distinguish success from failure is of little use. With the instanceof check, the local code for the sample stub then becomes (from page 1-114 of ptc/01-06-04): org.omg.CORBA.portable.ServantObject _so = _servant_preinvoke( "length", _opsClass ) ; if (_so == null) continue ; Example.AnInterfaceOperations _self = (Example.AnInterfaceOperations)_so.servant ; try { int result = _self.length(s) ; if (so instanceof ServantObjectExt) ((ServantObjectExt)so).normalCompletion() ; return result ; } catch (Throwable thr) { if (so instanceof ServantObjectExt) ((ServantObjectExt)so).exceptionalCompletion( thr ) ; throw thr ; } finally { _servant_postinvoke( _so ) ; } Note that the instanceof checks are quite fast in modern JVMs, so I don't think this adds significantly to the overhead of the operation. A reflective solution is also possible, but I am not including that here. In any case, the precise code generation should be left to the implementation. All that the spec should require is: 1. If the invocation on the servant completes without throwing an exception, then the stub code must call servant.normalCompletion after the invocation completes. 2. If the invocation on the servant throws exception exc, then the stub code must call servant.exceptionalCompletion( exc ) after the invocation completes. In either case, the servant completion call must occur before the _servant_postinvoke call. Resolution: Incorporate the revised text, make corresponding changes in the standard source files, close Revised Text: In section 1.21.6.3, add the class ServantObjectExt after ServantObject as follows: abstract public class ServantObjectExt extends ServantObject { abstract public void normalCompletion() ; abstract public void exceptionalCompletion( Throwable thr ) ; } In section 1.21.6.3, add a new paragraph before the last paragraph (the last paragraph begins "The _servant_postinvoke() method is invoked..."): If the ServantObject returned by the _servant_preinvoke() call is an instance of ServantObjectExt, the local invocation code must also satisfy the following conditions: If the invocation on the servant completes without throwing an exception, then the stub code must call servant.normalCompletion after the invocation completes. If the invocation on the servant throws exception exc, then the stub code must call servant.exceptionalCompletion( exc ) after the invocation completes. In either case, the servant completion call must occur before the _servant_postinvoke call. Note that an older stub may fail to satisfy these conditions. In this case, any request interceptors that run during local invocations will be unable to correctly report the completion of the request in the PortableInterceptor::RequestInfo reply_status field. In section 1.21.6.1, sub-section "Stream-base Stub Example", replace the local optimization (the last else clause) with: org.omg.CORBA.portable.ServantObject _so = _servant_preinvoke( "length", _opsClass ) ; if (_so == null) continue ; Example.AnInterfaceOperations _self = (Example.AnInterfaceOperations)_so.servant ; try { int result = _self.length(str) ; if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).normalCompletion() ; return result ; } catch (Example.AnException exc) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( exc ) ; throw exc ; } catch (RuntimeException re) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( re ) ; throw re ; } catch (Error err) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( err ) ; throw err ; } finally { _servant_postinvoke( _so ) ; } Actions taken: November 12, 2001: received issue May 13, 2002: closed issue Discussion: End of Annotations:===== Date: Mon, 12 Nov 2001 15:44:47 -0800 (PST) From: Ken Cavanaugh Reply-To: Ken Cavanaugh Subject: Colocated calls in Java To: issues@omg.org Cc: java-rtf@omg.org, ken.cavanaugh@sun.com MIME-Version: 1.0 Content-MD5: FpgeN1cXHo6UZXt+hwwQXw== X-Mailer: dtmail 1.3.0 @(#)CDE Version 1.3.5 SunOS 5.7 sun4u sparc Content-Type: TEXT/plain; charset=us-ascii X-UIDL: h>9e9HK'e9JJ)!!ElI!! Note: this is NOT issue 3754, but it is related. A new issue is needed as described below: -------------------------------------------------------------------------- Issue 3754 (colocated call optimization and portable interceptors) was raised some time ago by Harold Carr. This issue discusses the problems of supporting portable interceptors for RMI-IIOP calls when the colocated call optimization is used. The basic issue is that there is no way for the ORB to detect whether a local dispatch to a servant completed normally or completed by throwing an exception. This problem exists because the current is_local/servant_preinvoke/servant_postinvoke mechanism has no way to report normal or exceptional completion of a local dispatch. The same problem arises in the IDL stub case as well. Both Java mappings can share the same solution here, but a solution requires changing part of the portable stub API which is shared by both mappings. In the discussion of 3754, Simon Nash asked to reassign the issue from the Java to IDL RTF to the Java mapping RTF. We really need two separate issues here. I propose that we do the following: 1. Move 3754 back to the Java to IDL RTF since Harold wrote the issue with the RMI-IIOP mapping in mind. 2. Create a new Java mapping issue for the same problem. The bulk of this message should be the new issue. Both RTFs will need to consider the issues. The new Java mapping issue will need to propose extensions to the portable stub APIs and document the required changes in the IDL based stubs, while the resolution to 3754 will need to adopt the same new portable stub API and document the required changes in the RMI-IIOP stubs. To start a discussion, here is my initial proposal for solving this problem in the Java mapping RTF: We need to add methods to report the result of the local dispatch. I propose that we extend the portable definition of ServantObject as follows: abstract public class ServantObjectExt extends ServantObject { abstract public void normalCompletion() ; abstract public void exceptionalCompletion( Throwable thr ) ; } Another alternative is to extend the Delegate class instead. I prefer the ServantObject approach because the method signatures are simpler: adding these methods on the Delegate would require passing ServantObject as an argument, since multiple threads could be simultaneously invoking methods on the same object reference, which would share the same delegate. Making this change makes it necessary to consider what happens in mixed versions. Old stub, Old ServantObject: no change New stub, new ServantObject: stub always invokes either normalCompletion or exceptionalCompletion, so the ORB has enough information to correctly implement portable interceptor behavior. Note that a location forward (e.g. from a ServantManager) is not a problem today, since it happens inside of _servant_preinvoke, which allows the ORB to correctly handle that case. New stub, old ServantObject: If a new stub is written to do an instanceof check on the ServantObject it gets from _servant_preinvoke, it can correctly determine whether or not to call the new methods. There are a number of possibilities for the check: 1. Just use (so instanceof ServantObjectExt) and rely on the ServantObjectExt class to be defined somewhere in the environment. New stubs that wanted to be compatible with old ORBs would need to be packaged somehow with this class in their classpath. The stubs would need the ServantObjectExt class both at compile time and at runtime. 2. A stub could be written to entirely use reflection for the instanceof check and the method invocation. This would avoid the requirement to have ServantObjectExt in the classpath, but would require more code in the stubs, plus run a little slower (probably about 2X slower in JDK 1.4, but in earlier JDKs the penalty could easily be 10-20X). Old stub, new ServantObject: In this case, neither method is ever invoked, so the ORB can tell the difference between normal completion and an old stub. The PI implementation in this case is free to do anything. However, probably the best approach is to extend RequestInfo::reply_status with a new value PortableInterceptor::UNKNOWN. Then the local case would always use the interceptor points send_other and receive_other with a reply_status set to UNKNOWN. This extension requires a new core issue. It is worth noting here that the PI change makes it reasonable to consider simply changing PI, and avoid changing the ServantObject API and 2 language mappings. In this case, a user of PI cannot tell what is happening with colocated calls in a very basic sense: did the operation complete successfully or not? Many applications of PI (for example, transactions and security) often do not require the use of PI in the colocated case. However, one important application is best done this way: logging/tracing in a complex system. I believe this argues strongly for extending the mapping, since a log entry that cannot distinguish success from failure is of little use. With the instanceof check, the local code for the sample stub then becomes (from page 1-114 of ptc/01-06-04): org.omg.CORBA.portable.ServantObject _so = _servant_preinvoke( "length", _opsClass ) ; if (_so == null) continue ; Example.AnInterfaceOperations _self = (Example.AnInterfaceOperations)_so.servant ; try { int result = _self.length(s) ; if (so instanceof ServantObjectExt) ((ServantObjectExt)so).normalCompletion() ; return result ; } catch (Throwable thr) { if (so instanceof ServantObjectExt) ((ServantObjectExt)so).exceptionalCompletion( thr ) ; throw thr ; } finally { _servant_postinvoke( _so ) ; } Note that the instanceof checks are quite fast in modern JVMs, so I don't think this adds significantly to the overhead of the operation. A reflective solution is also possible, but I am not including that here. In any case, the precise code generation should be left to the implementation. All that the spec should require is: 1. If the invocation on the servant completes without throwing an exception, then the stub code must call servant.normalCompletion after the invocation completes. 2. If the invocation on the servant throws exception exc, then the stub code must call servant.exceptionalCompletion( exc ) after the invocation completes. In either case, the servant completion call must occur before the _servant_postinvoke call. Ken. Date: Tue, 18 Dec 2001 17:49:14 +0800 From: "M. Arshad Khan" Subject: Issue 4701: Colocated calls in Java To: java-rtf@omg.org Cc: Vijaykumar Natarajan , Muhammad Arshad Khan Message-id: <3C1F111A.6A0A8055@inprise.com> Organization: Inprise Singapore MIME-version: 1.0 X-Mailer: Mozilla 4.7 [en]C-CCK-MCD (WinNT; U) X-Accept-Language: en Content-Type: multipart/mixed; boundary="Boundary_(ID_Bvomef7OvyaOq0+ujz8UrA)" X-UIDL: 1!9!!`,gd9>'`d9Hi;!! Hello All, The proposed resolution for issue 4701 lists sample code for the stub. This code catches and rethrows a "Throwable". Java compiler will not compile this code since a Throwable is like a checked exception. A minor amendment is therefore proposed to the sample stub code: ..... try { int result = _self.length(s); if (so instanceof ServantObjectExt) ((ServantObjectExt)so).normalCompletion(); return result; } catch () { if (so instanceof ServantObjectExt) ((ServantObjectExt)so).exceptionalCompletion((Throwable)); throw ; } catch () { .... // other declared exceptions } catch (RuntimeException re) { if (so instanceof ServantObjectExt) ((ServantObjectExt)so).exceptionalCompletion((Throwable)re); throw re; } catch (java.lang.Error err) { if (so instanceof ServantObjectExt) ((ServantObjectExt)so).exceptionalCompletion((Throwable)err); throw err; } finally { servant_postinvoke(_so); } Regards Arshad Khan [] akhan.vcf Date: Tue, 18 Dec 2001 10:37:08 -0800 (PST) From: Ken Cavanaugh Reply-To: Ken Cavanaugh Subject: New issue: Error in 4701 resolution found by Arshad Kan To: issues@omg.org, java-rtf@omg.org MIME-Version: 1.0 Content-MD5: NKpcCaxhb8vYm9Gixl3DMA== X-Mailer: dtmail 1.3.0 @(#)CDE Version 1.3.5 SunOS 5.7 sun4u sparc Content-Type: TEXT/plain; charset=us-ascii X-UIDL: d1nd9jla!!F*Z!!)LXd9 >From Arshad Kan's email: >Hello All, > >The proposed resolution for issue 4701 lists sample code for the >stub. >This code catches and rethrows a "Throwable". Java compiler will not >compile this code since a Throwable is like a checked exception. A >minor >amendment is therefore proposed to the sample stub code: > >.... >try { > int result = _self.length(s); > if (so instanceof ServantObjectExt) > ((ServantObjectExt)so).normalCompletion(); > return result; >} catch () { > if (so instanceof ServantObjectExt) > ((ServantObjectExt)so).exceptionalCompletion((Throwable)exception>); > throw ; >} catch () { > .... // other declared exceptions >} catch (RuntimeException re) { > if (so instanceof ServantObjectExt) > ((ServantObjectExt)so).exceptionalCompletion((Throwable)re); > throw re; >} catch (java.lang.Error err) { > if (so instanceof ServantObjectExt) > ((ServantObjectExt)so).exceptionalCompletion((Throwable)err); > throw err; >} finally { > servant_postinvoke(_so); >} > >Regards >Arshad Khan > You are correct: the proposed resolution was incorrect as you stated. However, issue 4701 was passed as written in Vote 2. Therefore, we need to create a new issue to correct this problem. Proposed revised text: Replace the local optimization code as described in the resolution with the following: org.omg.CORBA.portable.ServantObject _so = _servant_preinvoke( "length", _opsClass ) ; if (_so == null) continue ; Example.AnInterfaceOperations _self = (Example.AnInterfaceOperations)_so.servant ; try { int result = _self.length(str) ; if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).normalCompletion() ; return result ; } catch (Example.AnException exc) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( exc ) ; throw exc ; } catch (RuntimeException re) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( re ) ; throw re ; } catch (Error err) { if (_so instanceof org.omg.CORBA.portable.ServantObjectExt) ((org.omg.CORBA.portable.ServantObjectExt)_so).exceptionalCompletion( err ) ; throw err ; } finally { _servant_postinvoke( _so ) ; } which actually compiles in the context of the example in the spec. Ken. Importance: Normal Subject: Re: Vote 4 To: Ken Cavanaugh Cc: java-rtf@omg.org X-Mailer: Lotus Notes Release 5.0.5 September 22, 2000 Message-ID: From: "Ann Dalton1" Date: Thu, 3 Jan 2002 18:16:36 +0000 X-MIMETrack: Serialize by Router on d06ml005/06/M/IBM(Release 5.0.8 |June 18, 2001) at 03/01/2002 22:09:59 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-UIDL: 8!`d9D"d!!6:2!!db_!! IBM votes YES on all issues in vote 4. I meant to add that I think a minor editorial change is needed to the updated example for issue 4701. The variable 'str' in changed sub-section 1.21.6.1, at line 8 should be 's' to be consistent with the rest of the example I think. Thanks, Ann ann_dalton@uk.ibm.com Ken Cavanaugh on 20/12/2001 17:54:44 Please respond to Ken Cavanaugh To: java-rtf@omg.org cc: Subject: Vote 4 Vote 4 is now available at http://cgi.omg.org/pub/javartf/Java_RTF_Vote_4.htm I had planned to include issues 3643 and 4057 in this vote, but I have not had time to write proposals for them, so they do not appear here. There are a few unusual aspects of this vote: 1. Issue 4701 was resolved in vote 2. It appears here because of a small correction needed to maintain backward compatibility. In this vote we are voting just for the change. I have included the entire resolution from vote 2 with the change highlighted so that everyone can see the change in context. 2. I wrote a single resolution for issues 4741, 4748, and 4750 which is labeled "joint resolution" in the vote. I did it this way because all three issues update the definitions of various ORB classes, and separating these would have made it very difficult to see the changes in context. If you wish to vote for individual issues on this vote, vote YES or NO on these three issues together. 3. 4749 is another minor fix, this time to issue 4699, which also passed in vote 2. As in the cas 4701, I have included the entire resolution to 4699, with the changes for 4749 highlighted. The vote here is for the change to the original resolution. The remainder of the vote is issues 4792, 4793, and 4794, which all have fairly simple proposals. Since we are rapidly approaching the holidays, I'll make this vote due on Thursday, January 3, 2002 at 5 pm PST. Thanks and Happy Holidays! Ken. Date: Thu, 3 Jan 2002 14:30:34 -0800 (PST) From: Ken Cavanaugh Reply-To: Ken Cavanaugh Subject: Re: Vote 4 To: Ken.Cavanaugh@sun.com, ann_dalton@uk.ibm.com Cc: java-rtf@omg.org MIME-Version: 1.0 Content-MD5: 30KhcT44HvyryWneftRJ9w== X-Mailer: dtmail 1.3.0 @(#)CDE Version 1.3.5 SunOS 5.7 sun4u sparc Content-Type: TEXT/plain; charset=us-ascii X-UIDL: e]id9$34!!k[Ke9L:%!! >Importance: Normal >Subject: Re: Vote 4 >To: Ken Cavanaugh >Cc: java-rtf@omg.org >From: "Ann Dalton1" >X-MIMETrack: Serialize by Router on d06ml005/06/M/IBM(Release 5.0.8 >|June 18, 2001) at 03/01/2002 22:09:59 >MIME-Version: 1.0 > > >IBM votes YES on all issues in vote 4. > >I meant to add that I think a minor editorial change is needed to >the updated example for issue 4701. The variable 'str' in changed >sub-section 1.21.6.1, at line 8 should be 's' to be consistent with >the rest of the example I think. > Thanks, you are right. I have made this small editorial change in the specification. Ken.