1. /*
  2. * @(#)GenericPOAClientSC.java 1.71 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.internal.POA;
  8. import org.omg.CORBA.*;
  9. import org.omg.CORBA.portable.*;
  10. import com.sun.corba.se.internal.core.*;
  11. import com.sun.corba.se.internal.core.NoSuchServiceContext ;
  12. import com.sun.corba.se.internal.core.DuplicateServiceContext ;
  13. import com.sun.corba.se.internal.orbutil.ORBUtility; //d11638
  14. import com.sun.corba.se.internal.orbutil.ORBConstants;
  15. import com.sun.corba.se.internal.corba.ClientDelegate;
  16. import com.sun.corba.se.internal.corba.ServerDelegate;
  17. import com.sun.corba.se.internal.iiop.Connection ;
  18. import com.sun.corba.se.internal.iiop.ClientRequestImpl;
  19. import com.sun.corba.se.internal.iiop.messages.ReplyMessage;
  20. import com.sun.corba.se.internal.ior.ObjectKeyTemplate ;
  21. import com.sun.corba.se.internal.ior.POAObjectKeyTemplate ;
  22. import com.sun.corba.se.internal.ior.POAId ;
  23. import com.sun.corba.se.internal.POA.POAORB ;
  24. import com.sun.corba.se.internal.orbutil.MinorCodes;
  25. /** The general-purpose client-side subcontract (delegate) for the POA ORB.
  26. * It handles client ORB processing for transient, persistent,
  27. * non-transactional and transactional server objects.
  28. * Its main functionality (in addition to the JavaIDL client subcontract) is:
  29. * - on each invocation, call the JTS Sender methods if the server object
  30. * is transactional.
  31. * - for persistent objects, first do a locate then invoke
  32. * The quality of service of the server object is known from the subcontract-id
  33. * variable ("scid").
  34. */
  35. public class GenericPOAClientSC extends ClientDelegate implements ClientSC
  36. {
  37. protected GenericPOAServerSC serversc ;
  38. public void setOrb( com.sun.corba.se.internal.core.ORB orb )
  39. {
  40. super.setOrb( orb ) ;
  41. serversc = (GenericPOAServerSC)orb.getSubcontractRegistry().getServerSubcontract(this.scid);
  42. }
  43. public boolean useLocalInvocation( org.omg.CORBA.Object self)
  44. {
  45. return orb.allowLocalOptimization && is_local( self ) ;
  46. }
  47. /** Return the objectid of the target POA objref associated with this
  48. * Delegate.
  49. */
  50. public byte[] getObjectId()
  51. {
  52. return getIOR().getProfile().getObjectId().getId() ;
  53. }
  54. /** Return the POAid of the target POA objref associated with this
  55. * Delegate.
  56. */
  57. public POAId getPOAId()
  58. {
  59. ObjectKeyTemplate oktemp = getIOR().getProfile().getTemplate().
  60. getObjectKeyTemplate() ;
  61. if (oktemp instanceof POAObjectKeyTemplate) {
  62. POAObjectKeyTemplate poktemp = (POAObjectKeyTemplate)oktemp ;
  63. POAId poaid = poktemp.getPOAId() ;
  64. if (orb.subcontractDebugFlag)
  65. dprint( "getPOAId() returns " + poaid ) ;
  66. return poaid ;
  67. } else
  68. throw new INTERNAL() ;
  69. }
  70. //Called by rmi-iiop's stream-based CORBA stubs.
  71. public InputStream invoke(org.omg.CORBA.Object self, OutputStream out)
  72. throws ApplicationException, RemarshalException
  73. {
  74. if (orb.subcontractDebugFlag)
  75. dprint( "invoke(org.omg.CORBA.Object,OutputStream) called" ) ;
  76. // We need to cast the orb to a POAORB so that we can invoke the
  77. // PI interception points:
  78. POAORB orb = (POAORB)this.orb;
  79. ClientRequest request = null;
  80. ClientResponse response = null;
  81. Exception exception = null;
  82. try {
  83. request = (ClientRequest) out;
  84. response = this.invoke(request);
  85. if (orb.subcontractDebugFlag)
  86. dprint( "invoke: response returned" ) ;
  87. // for oneway, since there is no response, there is no data to
  88. // be unmarhalled therefore skip to the releaseReply hooks. The
  89. // releaseReply hooks should take care of checking for null response
  90. if (request.isOneWay()) {
  91. // Invoke Portable Interceptors with receive_other
  92. exception = orb.invokeClientPIEndingPoint(
  93. ReplyMessage.NO_EXCEPTION, exception );
  94. continueOrThrowSystemOrRemarshal( exception );
  95. return null;
  96. }
  97. // COMMENT(Ram J) 10/01/2000 There is no need to set the response
  98. // stream's connection to that of the request stream. The response
  99. // stream will have a connection associated if the response
  100. // had been built out of the server response; else if the
  101. // response was built out of SystemException arising out of
  102. // response handling, then there will be no connection
  103. // or service context available with the response stream.
  104. // In such a case, the consumeServiceContexts has to return
  105. // gracefully.
  106. /*
  107. Connection c = request.getConnection();
  108. if (response != null && c != null )
  109. response.setConnection(c);
  110. */
  111. if (response.isSystemException()) {
  112. if (orb.subcontractDebugFlag)
  113. dprint( "invoke: reponse is system exception" ) ;
  114. SystemException se = response.getSystemException();
  115. if (orb.subcontractDebugFlag)
  116. dprint( "invoke: system exception " + se ) ;
  117. boolean doRemarshal = false;
  118. // FIX(Ram J) (04/28/2000) added locatedIOR = ior
  119. // and throw RemarshallException to force retrying
  120. // from root ior, if system exception is COMM_FAILURE.
  121. // WARNING: There is a risk of infinite loopback if the requests on
  122. // location forwarded ior result in system exception (COMM_FAILURE)
  123. if (se instanceof org.omg.CORBA.COMM_FAILURE
  124. && se.completed == CompletionStatus.COMPLETED_NO) {
  125. if (locatedIOR != ior) {
  126. locatedIOR = ior; // retry from root ior
  127. doRemarshal = true;
  128. if (orb.subcontractDebugFlag)
  129. dprint( "invoke: COMM_FAILURE retry" ) ;
  130. }
  131. }
  132. /* This used to live in a loop in IIOPOutputStream.invoke.
  133. That loop had a retry count to bound the number of tries.
  134. However that loop did not work once fragmentation was
  135. put in. So it was moved here. However, there is no
  136. place to hang the count since this throws out to the Stub.
  137. We need invocation level (i.e., thread local) date like
  138. in PI to put this count. That is scheduled for Taggart.
  139. For now, just turn this off.
  140. if (se.minor == MinorCodes.CONN_CLOSE_REBIND &&
  141. (se instanceof org.omg.CORBA.COMM_FAILURE)) {
  142. doRemarshal = true;
  143. }
  144. */
  145. if (doRemarshal) {
  146. // Invoke Portable Interceptors with receive_exception:
  147. exception = orb.invokeClientPIEndingPoint(
  148. ReplyMessage.SYSTEM_EXCEPTION, se );
  149. // If PI did not change the exception, throw a
  150. // Remarshal. Otherwise, throw the exception PI
  151. // wants thrown.
  152. if( se == exception ) {
  153. // The code before PI was added has exception null
  154. // at this point, so we maintain those semantics.
  155. exception = null;
  156. if (orb.subcontractDebugFlag)
  157. dprint( "invoke: throwing ReMarshal exception" ) ;
  158. throw new RemarshalException();
  159. }
  160. else {
  161. continueOrThrowSystemOrRemarshal( exception );
  162. throw new INTERNAL(
  163. "Assertion failed. " +
  164. "exception should not be null." );
  165. }
  166. }
  167. if (orb.subcontractDebugFlag)
  168. dprint( "invoke: processing response service contexts" ) ;
  169. ServiceContexts contexts = response.getServiceContexts();
  170. if (contexts != null) {
  171. try {
  172. UEInfoServiceContext usc =
  173. (UEInfoServiceContext)(contexts.get(
  174. UEInfoServiceContext.SERVICE_CONTEXT_ID )) ;
  175. Throwable unknown = usc.getUE() ;
  176. UnknownException ue = new UnknownException(unknown);
  177. // Invoke Portable Interceptors with receive_exception:
  178. exception = orb.invokeClientPIEndingPoint(
  179. ReplyMessage.SYSTEM_EXCEPTION, ue );
  180. continueOrThrowSystemOrRemarshal( exception );
  181. throw new INTERNAL(
  182. "Assertion failed. exception should not be null.");
  183. } catch (NoSuchServiceContext exc) {
  184. // NO-OP: handled by system exception below
  185. }
  186. }
  187. // Invoke Portable Interceptors with receive_exception:
  188. exception = orb.invokeClientPIEndingPoint(
  189. ReplyMessage.SYSTEM_EXCEPTION, se );
  190. continueOrThrowSystemOrRemarshal( exception );
  191. // Note: We should never need to execute this line, but
  192. // we should assert in case exception was set to null somehow.
  193. throw new INTERNAL(
  194. "Assertion failed: exception should not be null." );
  195. } else if (response.isUserException()) {
  196. if (orb.subcontractDebugFlag)
  197. dprint( "invoke: response is user exception" ) ;
  198. ApplicationException appException =
  199. new ApplicationException(response.peekUserExceptionId(),
  200. (org.omg.CORBA.portable.InputStream)response);
  201. // Invoke Portable Interceptors with receive_exception
  202. // (user exception):
  203. exception = orb.invokeClientPIEndingPoint(
  204. ReplyMessage.USER_EXCEPTION, appException );
  205. if( exception != appException ) {
  206. continueOrThrowSystemOrRemarshal( exception );
  207. }
  208. throw (ApplicationException)exception;
  209. } else if (response.isLocationForward()) {
  210. if (orb.subcontractDebugFlag)
  211. dprint( "invoke: response is location forward" ) ;
  212. // In this case the exception is not handed to JTS sender.
  213. // Need to check spec on this!
  214. // FIX(Ram J) (04/28/2000) added setting locatedIOR. Also the
  215. // above assertion "exception is not handled to JTS sender.."
  216. // is not true anymore. The JTS sender hook is called for
  217. // every location forwarded ior if the ior is transactional.
  218. locatedIOR = response.getForwardedIOR();
  219. // Invoke Portable Interceptors with receive_other:
  220. Exception newException = orb.invokeClientPIEndingPoint(
  221. ReplyMessage.LOCATION_FORWARD, null );
  222. // Even if no interceptors are registered,
  223. // invokeClientPIEndingPoint will return RemarshalException
  224. // because LOCATION_FORWARD was passed in. We want to
  225. // preserve the state of the "exception" variable to be
  226. // null in this case so that the finally block works the
  227. // way it did before we introduced PI. In the case of a
  228. // SystemException, however, we do want the "exception"
  229. // variable set.
  230. if( !(newException instanceof RemarshalException) ) {
  231. exception = newException;
  232. }
  233. // If PI did not raise exception, throw Remarshal, else
  234. // throw the exception PI wants thrown.
  235. continueOrThrowSystemOrRemarshal( exception );
  236. throw new RemarshalException();
  237. } else if (response.isDifferentAddrDispositionRequested()) {
  238. if (orb.subcontractDebugFlag)
  239. dprint( "invoke: response is NEEDS_ADDRESSING_MODE" ) ;
  240. // set the desired target addressing disposition.
  241. addressingDisposition = response.getAddrDisposition();
  242. // Invoke Portable Interceptors with receive_other:
  243. Exception newException = orb.invokeClientPIEndingPoint(
  244. ReplyMessage.NEEDS_ADDRESSING_MODE, null );
  245. // Even if no interceptors are registered,
  246. // invokeClientPIEndingPoint will return RemarshalException
  247. // because NEEDS_ADDRESSING_MODE was passed in. We want to
  248. // preserve the state of the "exception" variable to be
  249. // null in this case so that the finally block works the
  250. // way it did before we introduced PI. In the case of a
  251. // SystemException, however, we do want the "exception"
  252. // variable set.
  253. if( !(newException instanceof RemarshalException) ) {
  254. exception = newException;
  255. }
  256. // If PI did not raise exception, throw Remarshal, else
  257. // throw the exception PI wants thrown.
  258. continueOrThrowSystemOrRemarshal( exception );
  259. throw new RemarshalException();
  260. } else /* normal response */ {
  261. if (orb.subcontractDebugFlag)
  262. dprint( "invoke: response is normal" ) ;
  263. // Invoke Portable Interceptors with receive_reply:
  264. exception = orb.invokeClientPIEndingPoint(
  265. ReplyMessage.NO_EXCEPTION, null );
  266. // Remember: not thrown if exception is null.
  267. continueOrThrowSystemOrRemarshal( exception );
  268. return (InputStream) response;
  269. }
  270. } finally {
  271. // _REVISIT_ PI Note: Any exceptions in the following try block
  272. // happen after PI endpoint has already run so they are not
  273. // reported to interceptors.
  274. try {
  275. //Call JTS sender's received_reply
  276. this.releaseReply( response, request.getOperationName(),
  277. exception);
  278. } catch ( WrongTransaction ex ) {
  279. // XXX return this for deferred sends
  280. throw new NO_IMPLEMENT(
  281. com.sun.corba.se.internal.orbutil.MinorCodes.SEND_DEFERRED_NOTIMPLEMENTED,
  282. CompletionStatus.COMPLETED_MAYBE);
  283. } catch ( SystemException ex ) {
  284. throw ex;
  285. }
  286. }
  287. }
  288. // Filters the given exception into a SystemException or a
  289. // RemarshalException and throws it. Assumes the given exception is
  290. // of one of these two types. This is a utility method for
  291. // the above invoke code which must do this numerous times.
  292. // If the exception is null, no exception is thrown.
  293. //
  294. // Note that this code is duplicated in ClientDelegate.java
  295. private void continueOrThrowSystemOrRemarshal( Exception exception )
  296. throws SystemException, RemarshalException
  297. {
  298. if( exception == null ) {
  299. // do nothing.
  300. }
  301. else if( exception instanceof RemarshalException ) {
  302. throw (RemarshalException)exception;
  303. }
  304. else {
  305. throw (SystemException)exception;
  306. }
  307. }
  308. public ServiceContexts getServiceContexts(
  309. Connection c, int requestId, String opName, boolean isOneWay, GIOPVersion gv )
  310. {
  311. ServiceContexts scs = super.getServiceContexts(
  312. c, requestId, opName, isOneWay, gv ) ;
  313. ServiceContext txsc = null ;
  314. if (locatedIOR.isTransactional() && !isSpecialMethod(opName) &&
  315. !locatedIOR.isLocal())
  316. txsc = ((POAORB)(orb)).getTxServiceContext( requestId ) ;
  317. if (txsc != null)
  318. try {
  319. scs.put( txsc ) ;
  320. } catch (DuplicateServiceContext dsc) {
  321. // This should never happen
  322. throw new INTERNAL() ;
  323. }
  324. // call interceptor hooks if any are defined
  325. ((POAORB)orb).sendingRequestServiceContexts( scs ) ;
  326. return scs ;
  327. }
  328. // Invoked by DII layer (from RequestImpl.doInvocation())
  329. // after unmarshaling reply and exceptions.
  330. public void releaseReply(ClientResponse resp, String method,
  331. Exception exception)
  332. throws WrongTransaction, SystemException
  333. {
  334. receivedReply(resp, method, exception);
  335. }
  336. private final boolean isTransient(int subcontractId)
  337. {
  338. // 2nd bit in subcontract id is 0 for transient case.
  339. return ((subcontractId & 2)==0);
  340. }
  341. protected IOR locate()
  342. {
  343. if ( isTransient(scid) ) // don't locate for transient objects
  344. return ior;
  345. else {
  346. ClientGIOP giop = orb.getClientGIOP();
  347. return giop.locate(ior);
  348. }
  349. }
  350. public ServantObject servant_preinvoke(org.omg.CORBA.Object self,
  351. String operation,
  352. Class expectedType)
  353. {
  354. ServantObject servantObject = serversc.preinvoke(ior,
  355. operation, expectedType);
  356. // This is to make sure that local invocation does not result
  357. // in an infinite loop, in case servant_preinvoke cannot find
  358. // the servant Object.
  359. // To understand how this works, see the comments in
  360. // ClientDelegate.servant_preinvoke
  361. if( servantObject == null ) {
  362. isNextIsLocalValid.set( Boolean.FALSE );
  363. }
  364. return servantObject;
  365. }
  366. public void servant_postinvoke(org.omg.CORBA.Object self,
  367. ServantObject servantobj)
  368. {
  369. serversc.postinvoke(ior, servantobj);
  370. }
  371. /** Deliver the reply transaction context and any exception to JTS.
  372. */
  373. protected void receivedReply(ClientResponse resp, String method,
  374. Exception exception)
  375. throws WrongTransaction, SystemException
  376. {
  377. if (resp != null) { // do processing for two way calls, since
  378. // response is not null in that case
  379. // The Interceptor writer should take care
  380. // of invoking hooks in oneway case
  381. // consume any others that may be defined
  382. POAORB myorb = (POAORB) orb;
  383. ServiceContexts svcCtxList = resp.getServiceContexts();
  384. // If handleTxServiceContext throws an exception,
  385. // old interceptor hooks are not called. This is
  386. // the way this used to work, but is probably not
  387. // optimal.
  388. if (locatedIOR.isTransactional() && !isSpecialMethod(method) &&
  389. !locatedIOR.isLocal())
  390. ((POAORB)(orb)).handleTxServiceContext( svcCtxList,
  391. exception, resp.getRequestId() ) ;
  392. // call any hooks that are defined
  393. try {
  394. myorb.receivedReplyServiceContexts(svcCtxList);
  395. } catch (Throwable ex) {
  396. ; //Do not let hook errors escape.
  397. }
  398. }
  399. }
  400. protected boolean isSpecialMethod(String method)
  401. {
  402. if (method.startsWith("_") &&
  403. !method.startsWith("_get_") &&
  404. !method.startsWith("_set_"))
  405. return true;
  406. else
  407. return false;
  408. }
  409. }