1. /*
  2. * @(#)ServerDelegate.java 1.72 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. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.internal.corba;
  16. import javax.rmi.CORBA.Tie;
  17. import org.omg.CORBA.portable.ApplicationException;
  18. import org.omg.CORBA.SystemException;
  19. import org.omg.CORBA.INTERNAL;
  20. import org.omg.CORBA.UNKNOWN;
  21. import org.omg.CORBA.OBJECT_NOT_EXIST;
  22. import org.omg.CORBA.DATA_CONVERSION;
  23. import org.omg.CORBA.CompletionStatus;
  24. import org.omg.CORBA.Any;
  25. import org.omg.CORBA.portable.ObjectImpl;
  26. import org.omg.CORBA.portable.InvokeHandler;
  27. import org.omg.CORBA.DynamicImplementation;
  28. import org.omg.CORBA.portable.InputStream;
  29. import org.omg.CORBA.portable.OutputStream;
  30. import org.omg.CORBA.portable.UnknownException;
  31. import org.omg.CORBA.CompletionStatus;
  32. import java.rmi.Remote;
  33. import com.sun.corba.se.internal.iiop.ORB;
  34. import com.sun.corba.se.internal.core.InternalRuntimeForwardRequest;
  35. import com.sun.corba.se.internal.core.ServerSubcontract;
  36. import com.sun.corba.se.internal.core.IOR;
  37. import com.sun.corba.se.internal.core.ServerRequest;
  38. import com.sun.corba.se.internal.core.ServerResponse;
  39. import com.sun.corba.se.internal.core.ServiceContext;
  40. import com.sun.corba.se.internal.core.DuplicateServiceContext;
  41. import com.sun.corba.se.internal.core.NoSuchServiceContext;
  42. import com.sun.corba.se.internal.core.ServiceContexts;
  43. import com.sun.corba.se.internal.core.UEInfoServiceContext;
  44. import com.sun.corba.se.internal.core.CodeSetServiceContext;
  45. import com.sun.corba.se.internal.core.SendingContextServiceContext;
  46. import com.sun.corba.se.internal.core.ORBVersionServiceContext;
  47. import com.sun.corba.se.internal.core.ORBVersion;
  48. import com.sun.corba.se.internal.core.ORBVersionFactory;
  49. import com.sun.corba.se.internal.core.ORBVersionImpl;
  50. import com.sun.corba.se.internal.core.EndPoint;
  51. import com.sun.corba.se.internal.core.ClientSubcontract;
  52. import com.sun.corba.se.internal.core.ServiceContext;
  53. import com.sun.corba.se.internal.core.MarshalInputStream;
  54. import com.sun.corba.se.internal.core.MarshalOutputStream;
  55. import com.sun.corba.se.internal.core.CodeSetComponentInfo;
  56. import com.sun.corba.se.internal.core.GIOPVersion;
  57. import com.sun.corba.se.internal.core.OSFCodeSetRegistry;
  58. import com.sun.corba.se.internal.orbutil.MinorCodes;
  59. import com.sun.corba.se.internal.orbutil.ORBUtility;
  60. import com.sun.org.omg.SendingContext.CodeBase;
  61. import com.sun.corba.se.internal.orbutil.TransientObjectManager;
  62. import com.sun.corba.se.internal.orbutil.ORBConstants;
  63. import com.sun.corba.se.internal.iiop.Connection;
  64. import com.sun.corba.se.internal.iiop.RequestCanceledException;
  65. import com.sun.corba.se.internal.ior.ObjectId;
  66. import com.sun.corba.se.internal.ior.ObjectKeyFactory;
  67. import com.sun.corba.se.internal.ior.ObjectKey;
  68. import com.sun.corba.se.internal.ior.ObjectKeyTemplate;
  69. import com.sun.corba.se.internal.ior.JIDLObjectKeyTemplate;
  70. public class ServerDelegate implements ServerSubcontract {
  71. protected void dprint( String msg )
  72. {
  73. ORBUtility.dprint( this, msg ) ;
  74. }
  75. protected ORB orb; // my ORB instance
  76. protected int scid; // my subcontract id
  77. protected TransientObjectManager servants;
  78. // Added from last version because it broke the build - RTW
  79. public static final int UNKNOWN_EXCEPTION_INFO_ID = 9;
  80. // These offsets are for the object key. Assume the first 8 bytes
  81. // contain the magic and the sc-id.
  82. public static final int SERVERID_OFFSET = 8;
  83. public static final int USERKEYLEN_OFFSET = 12;
  84. public static final int USERKEY_OFFSET = 16;
  85. public ServerDelegate() {
  86. servants = new TransientObjectManager();
  87. }
  88. public ServerDelegate(ORB orb) {
  89. this();
  90. setOrb( orb ) ;
  91. }
  92. public void setId(int id) {
  93. this.scid = id;
  94. }
  95. public int getId()
  96. {
  97. return scid ;
  98. }
  99. public void setOrb(com.sun.corba.se.internal.core.ORB orb) {
  100. this.orb = (com.sun.corba.se.internal.iiop.ORB) orb;
  101. servants.setOrb( (com.sun.corba.se.internal.corba.ORB)orb ) ;
  102. }
  103. public Class getClientSubcontractClass() {
  104. return ClientDelegate.class;
  105. }
  106. // Need to signal one of OBJECT_HERE, OBJECT_FORWARD, OBJECT_NOT_EXIST.
  107. public IOR locate(ObjectKey okey) {
  108. ObjectId id = okey.getId() ;
  109. ObjectKeyTemplate oktemp = okey.getTemplate() ;
  110. // Check if the serverid matches this server's transientServerId.
  111. int sid = oktemp.getServerId() ;
  112. if ( sid != orb.getTransientServerId() )
  113. throw new OBJECT_NOT_EXIST(MinorCodes.BAD_SERVER_ID,
  114. CompletionStatus.COMPLETED_NO);
  115. // Get the servant
  116. java.lang.Object servant = getServant(id);
  117. if (servant == null)
  118. throw new OBJECT_NOT_EXIST(MinorCodes.SERVANT_NOT_FOUND,
  119. CompletionStatus.COMPLETED_NO);
  120. // If we reached here, it means we got the servant,
  121. // so just return null to signal OBJECT_HERE.
  122. return null;
  123. }
  124. private Object getServant( ObjectId id )
  125. {
  126. byte[] userKey = id.getId() ;
  127. return servants.lookupServant(userKey);
  128. }
  129. public Object getServant(IOR ior) {
  130. if (!ior.isLocal())
  131. return null;
  132. ObjectId id = ior.getProfile().getObjectId() ;
  133. return getServant( id ) ;
  134. }
  135. public boolean isServantSupported() {
  136. return true;
  137. }
  138. public void consumeServiceContexts(ServerRequest request) {
  139. ServiceContexts ctxts = request.getServiceContexts();
  140. ServiceContext sc ;
  141. GIOPVersion giopVersion = request.getGIOPVersion();
  142. // we cannot depend on this since for our local case, we do not send
  143. // in this service context. Can we rely on just the CodeSetServiceContext?
  144. // boolean rtSC = false; // Runtime ServiceContext
  145. boolean hasCodeSetContext = processCodeSetContext(request, ctxts);
  146. if (orb.subcontractDebugFlag) {
  147. dprint("Consuming service contexts, GIOP version: " + giopVersion);
  148. dprint("Has code set context? " + hasCodeSetContext);
  149. }
  150. try {
  151. sc = ctxts.get(
  152. SendingContextServiceContext.SERVICE_CONTEXT_ID ) ;
  153. SendingContextServiceContext scsc =
  154. (SendingContextServiceContext)sc ;
  155. IOR ior = scsc.getIOR() ;
  156. try {
  157. request.getConnection().setCodeBaseIOR(ior);
  158. } catch (ThreadDeath td) {
  159. throw td ;
  160. } catch (Throwable t) {
  161. throw new DATA_CONVERSION( MinorCodes.BAD_STRINGIFIED_IOR,
  162. CompletionStatus.COMPLETED_NO);
  163. }
  164. } catch (NoSuchServiceContext exc) {
  165. // ignore: this type not present
  166. }
  167. // the RTSC is sent only once during session establishment. We
  168. // need to find out if the CodeBaseRef is already set. If yes,
  169. // then also the rtSC flag needs to be set to true
  170. // this is not possible for the LocalCase since there is no
  171. // IIOPConnection for the LocalCase
  172. // used for a case where we have JDK 1.3 supporting 1.0 protocol,
  173. // but sending 2 service contexts, that is not normal as per
  174. // GIOP rules, based on above information, we figure out that we
  175. // are talking to the legacy ORB and set the ORB Version Accordingly.
  176. // this special case tell us that it is legacy SUN orb
  177. // and not a foreign one
  178. // rtSC is not available for localcase due to which this generic
  179. // path would fail if relying on rtSC
  180. //if (giopVersion.equals(GIOPVersion.V1_0) && hasCodeSetContext && rtSC)
  181. boolean isForeignORB = false;
  182. if (giopVersion.equals(GIOPVersion.V1_0) && hasCodeSetContext) {
  183. if (orb.subcontractDebugFlag)
  184. dprint("Determined to be an old Sun ORB");
  185. orb.setORBVersion(ORBVersionImpl.OLD) ;
  186. // System.out.println("setting legacy ORB version");
  187. } else {
  188. // If it didn't include our ORB version service context (below),
  189. // then it must be a foreign ORB.
  190. isForeignORB = true;
  191. }
  192. // try to get the ORBVersion sent as part of the ServiceContext
  193. // if any
  194. try {
  195. sc = ctxts.get( ORBVersionServiceContext.SERVICE_CONTEXT_ID ) ;
  196. ORBVersionServiceContext ovsc =
  197. (ORBVersionServiceContext) sc;
  198. ORBVersion version = ovsc.getVersion();
  199. orb.setORBVersion( version ) ;
  200. isForeignORB = false;
  201. } catch (NoSuchServiceContext exc) {
  202. // ignore: this type not present
  203. }
  204. if (isForeignORB) {
  205. if (orb.subcontractDebugFlag)
  206. dprint("Determined to be a foreign ORB");
  207. orb.setORBVersion(ORBVersionImpl.FOREIGN);
  208. }
  209. }
  210. public ServerResponse dispatch(ServerRequest request) {
  211. if (orb.subcontractDebugFlag)
  212. dprint( "Entering dispatch method" ) ;
  213. ObjectKey okey = request.getObjectKey();
  214. ObjectKeyTemplate oktemp = okey.getTemplate() ;
  215. ObjectId oid = okey.getId() ;
  216. String operation = request.getOperationName();
  217. Object servant = getServant(oid);
  218. if (servant == null) {
  219. boolean raiseObjectNotExist = true;
  220. if (SpecialMethod.isSpecialMethod(operation)) {
  221. SpecialMethod specialMethod =
  222. SpecialMethod.getSpecialMethod(operation);
  223. if (specialMethod instanceof NonExistent ||
  224. specialMethod instanceof NotExistent)
  225. {
  226. raiseObjectNotExist = false;
  227. }
  228. }
  229. if (raiseObjectNotExist) {
  230. throw new OBJECT_NOT_EXIST(MinorCodes.SERVANT_NOT_FOUND,
  231. CompletionStatus.COMPLETED_NO);
  232. }
  233. }
  234. ServerResponse response = null;
  235. int sId = oktemp.getServerId() ;
  236. if (sId != orb.getTransientServerId())
  237. throw new OBJECT_NOT_EXIST(MinorCodes.BAD_SERVER_ID,
  238. CompletionStatus.COMPLETED_NO);
  239. consumeServiceContexts(request);
  240. // Now that we have the service contexts processed and the
  241. // correct ORBVersion set, we must finish initializing the
  242. // stream.
  243. request.performORBVersionSpecificInit();
  244. if (orb.subcontractDebugFlag)
  245. dprint( "Dispatching to servant" ) ;
  246. // This outer try is required for PI so that if an interceptor
  247. // throws InternalRuntimeForwardRequest in a send_* point,
  248. // we can still handle it.
  249. try {
  250. try {
  251. // Notify PI of serverRequest, Servant.
  252. // Note that we call receive_request_service_contexts after
  253. // setting the servant in the info object. This is
  254. // different than in the POA case (see GenericPOAServerSC),
  255. // but OK since this case is not covered by the spec
  256. // anyway.
  257. ((com.sun.corba.se.internal.corba.ORB)orb).
  258. initializeServerPIInfo( request, null,
  259. oid.getId(), oktemp.getAdapterId( orb ) );
  260. // Note: we do not know the MDI on a null servant.
  261. // We only end up in that situation if _non_existent called.
  262. ((com.sun.corba.se.internal.corba.ORB)orb).
  263. setServerPIInfo( servant,
  264. (servant == null ?
  265. "unknown" :
  266. ((ObjectImpl)servant)._ids()[0]) );
  267. // Invoke server starting interception points:
  268. ((com.sun.corba.se.internal.corba.ORB)orb).
  269. invokeServerPIStartingPoint();
  270. // Note: org.omg.CORBA.DynamicImplementation is deprecated!
  271. if( ((servant != null) &&
  272. !(servant instanceof DynamicImplementation) ) ||
  273. SpecialMethod.isSpecialMethod( operation ) )
  274. {
  275. ((com.sun.corba.se.internal.corba.ORB)orb).
  276. invokeServerPIIntermediatePoint();
  277. }
  278. if (SpecialMethod.isSpecialMethod(operation)) {
  279. if (orb.subcontractDebugFlag)
  280. dprint( "Handling special method" ) ;
  281. response = SpecialMethod.getSpecialMethod(
  282. operation).invoke(servant, request);
  283. } else if (servant instanceof InvokeHandler) {
  284. if (orb.subcontractDebugFlag)
  285. dprint( "Handling invoke handler type servant" ) ;
  286. response = (ServerResponse)((InvokeHandler)servant)._invoke(
  287. operation, (org.omg.CORBA.portable.InputStream) request,
  288. request);
  289. } else {
  290. if (orb.subcontractDebugFlag)
  291. dprint( "Handling DSI type servant" ) ;
  292. // Invoke on servant using DSI
  293. ServerRequestImpl sreq = new ServerRequestImpl(request,
  294. orb);
  295. DynamicImplementation dServant =
  296. (DynamicImplementation)servant;
  297. OutputStream os;
  298. InputStream is = (InputStream) request;
  299. dServant.invoke(sreq);
  300. // Check if ServerRequestImpl.result() has been called
  301. Any excany = sreq.checkResultCalled();
  302. if ( excany == null ) { // normal return
  303. if (orb.subcontractDebugFlag)
  304. dprint( "DSI type servant: normal response" ) ;
  305. response = request.createResponse(null);
  306. // Marshal out/inout/return parameters into the
  307. // ReplyMessage
  308. os = (OutputStream) response;
  309. sreq.marshalReplyParams(os);
  310. } else {
  311. if (orb.subcontractDebugFlag)
  312. dprint( "DSI type servant: error response" ) ;
  313. // Check if the servant set a SystemException or
  314. // UserException
  315. String repId = excany.type().id();
  316. if (ORBUtility.isSystemException(repId)) {
  317. if (orb.subcontractDebugFlag)
  318. dprint( "DSI type servant: system exception" ) ;
  319. // Get the exception object from the Any
  320. InputStream in = excany.create_input_stream();
  321. SystemException ex =
  322. ORBUtility.readSystemException(in);
  323. // Marshal the exception back
  324. response = request.createSystemExceptionResponse(
  325. ex, null);
  326. } else {
  327. if (orb.subcontractDebugFlag)
  328. dprint( "DSI type servant: user exception" ) ;
  329. response =
  330. request.createUserExceptionResponse(null);
  331. os = (OutputStream) response;
  332. excany.write_value(os);
  333. }
  334. }
  335. }
  336. } catch (InternalRuntimeForwardRequest ex ) {
  337. // In case PI throws a ForwardRequest:
  338. // Get the IOR from the ForwardRequest and send it back.
  339. response = handleInternalRuntimeForwardRequest(
  340. request, (ObjectImpl)ex.forward );
  341. } catch (UnknownException ex) {
  342. if (orb.subcontractDebugFlag)
  343. dprint( "After dispatch: Unknown exception " + ex ) ;
  344. // RMIC generated tie skeletons convert all Throwable exception
  345. // types (including RequestCanceledException, ThreadDeath)
  346. // thrown during reading fragments into UnknownException.
  347. // If RequestCanceledException was indeed raised,
  348. // then rethrow it, which will eventually cause the worker
  349. // thread to unstack the dispatch and wait for other requests.
  350. if (ex.originalEx instanceof RequestCanceledException) {
  351. throw (RequestCanceledException) ex.originalEx;
  352. }
  353. ServiceContexts contexts = new ServiceContexts( orb ) ;
  354. UEInfoServiceContext usc = new UEInfoServiceContext(
  355. ex.originalEx ) ;
  356. try {
  357. contexts.put( usc ) ;
  358. } catch (DuplicateServiceContext dsc) {
  359. // Can't happen, since we are adding usc to an empty
  360. // contexts object
  361. }
  362. SystemException sys = new UNKNOWN( 0,
  363. CompletionStatus.COMPLETED_MAYBE);
  364. response = request.createSystemExceptionResponse(sys,contexts);
  365. } catch (RequestCanceledException ex) {
  366. // IDLJ generated non-tie based skeletons do not catch the
  367. // RequestCanceledException. Rethrow the exception, which will
  368. // cause the worker thread to unwind the dispatch and wait for
  369. // other requests.
  370. throw ex;
  371. } catch (Throwable ex) {
  372. if (orb.subcontractDebugFlag)
  373. dprint( "After dispatch: other exception " + ex ) ;
  374. response =
  375. orb.handleThrowableDuringServerDispatch(
  376. request,
  377. ex,
  378. CompletionStatus.COMPLETED_MAYBE);
  379. }
  380. }
  381. catch( InternalRuntimeForwardRequest re ) {
  382. // In case PI throws a ForwardRequest:
  383. // Get the IOR from the ForwardRequest and send it back.
  384. response = handleInternalRuntimeForwardRequest(
  385. request, (ObjectImpl)re.forward );
  386. }
  387. return response;
  388. }
  389. /**
  390. * Private utility method to handle PI internal runtime forwardrequest
  391. * and create the appropriate location forward response for it.
  392. */
  393. private ServerResponse handleInternalRuntimeForwardRequest(
  394. ServerRequest request, ObjectImpl foi )
  395. {
  396. ClientSubcontract delegate =
  397. (ClientSubcontract)foi._get_delegate();
  398. IOR ior = delegate.marshal();
  399. return request.createLocationForward( ior, null );
  400. }
  401. public void destroyObjref(Object objref) {
  402. // Get the delegate, then ior, then transientKey, then delete servant
  403. ObjectImpl oi = (ObjectImpl)objref;
  404. ClientSubcontract del = (ClientSubcontract)oi._get_delegate();
  405. IOR ior = del.marshal();
  406. ObjectId id = ior.getProfile().getObjectId() ;
  407. byte[] transientKey = id.getId() ;
  408. servants.deleteServant(transientKey);
  409. del.unexport();
  410. }
  411. public Object createObjref(IOR ior) {
  412. throw new INTERNAL( MinorCodes.WRONG_CLIENTSC,
  413. CompletionStatus.COMPLETED_MAYBE);
  414. }
  415. public Object createObjref(byte[] key, Object servant) {
  416. // Note that the key parameter is never used here.
  417. // First, make sure this is an ObjectImpl.
  418. ObjectImpl objectImpl = (ObjectImpl) servant;
  419. // Store it and get a userkey allocated by the transient
  420. // object manager.
  421. key = servants.storeServant(objectImpl, null);
  422. ObjectId oid = new ObjectId( key ) ;
  423. ObjectKeyTemplate oktemp = new JIDLObjectKeyTemplate( scid,
  424. orb.getTransientServerId() ) ;
  425. ObjectKey okey = new ObjectKey( oktemp, oid ) ;
  426. // Find out the repository ID for this servant.
  427. String id = getId(objectImpl);
  428. // Find out the port number to put in the IOR.
  429. EndPoint endpoint = orb.getServerGIOP().getDefaultEndpoint();
  430. if (endpoint == null) {
  431. orb.getServerGIOP().initEndpoints();
  432. endpoint = orb.getServerGIOP().getDefaultEndpoint();
  433. }
  434. int port = endpoint.getPort();
  435. String host = endpoint.getHostName();
  436. IOR ior = new IOR( orb, id, host, port, okey, servant ) ;
  437. // Create the delegate and set it in the tie
  438. ClientDelegate delegate = new ClientDelegate( orb,
  439. ior, this.scid, servant ) ;
  440. objectImpl._set_delegate( delegate ) ;
  441. return objectImpl ;
  442. }
  443. public static String getId(ObjectImpl theTie) {
  444. return theTie._ids()[0];
  445. }
  446. /**
  447. * Handles setting the connection's code sets if required.
  448. * Returns true if the CodeSetContext was in the request, false
  449. * otherwise.
  450. */
  451. private boolean processCodeSetContext(ServerRequest request,
  452. ServiceContexts contexts) {
  453. try {
  454. ServiceContext sc = contexts.get(CodeSetServiceContext.SERVICE_CONTEXT_ID);
  455. // Somehow a code set service context showed up in the local case.
  456. if (request.getConnection() == null) {
  457. return true;
  458. }
  459. // If it's GIOP 1.0, it shouldn't have this context at all. Our legacy
  460. // ORBs sent it and we need to know if it's here to make ORB versioning
  461. // decisions, but we don't use the contents.
  462. if (request.getGIOPVersion().equals(GIOPVersion.V1_0)) {
  463. return true;
  464. }
  465. CodeSetServiceContext cssc = (CodeSetServiceContext)sc ;
  466. CodeSetComponentInfo.CodeSetContext csctx = cssc.getCodeSetContext();
  467. // Note on threading:
  468. //
  469. // getCodeSetContext and setCodeSetContext are synchronized
  470. // on the Connection. At worst, this will result in
  471. // multiple threads entering this block and calling
  472. // setCodeSetContext but not actually changing the
  473. // values on the Connection.
  474. //
  475. // Alternative would be to lock the connection for the
  476. // whole block, but it's fine either way.
  477. //
  478. // The connection's codeSetContext is null until we've received a
  479. // request with a code set context with the negotiated code sets.
  480. if (request.getConnection().getCodeSetContext() == null) {
  481. // Use these code sets on this connection
  482. if (orb.subcontractDebugFlag)
  483. dprint("Setting code sets to: " + csctx);
  484. request.getConnection().setCodeSetContext(csctx);
  485. // We had to read the method name using ISO 8859-1
  486. // (which is the default in the CDRInputStream for
  487. // char data), but now we may have a new char
  488. // code set. If it isn't ISO8859-1, we must tell
  489. // the CDR stream to null any converter references
  490. // it has created so that it will reacquire
  491. // the code sets again using the new info.
  492. //
  493. // This should probably compare with the stream's
  494. // char code set rather than assuming it's ISO8859-1.
  495. // (However, the operation name is almost certainly
  496. // ISO8859-1 or ASCII.)
  497. if (csctx.getCharCodeSet()
  498. != OSFCodeSetRegistry.ISO_8859_1.getNumber()) {
  499. request.resetCodeSetConverters();
  500. }
  501. }
  502. return true;
  503. } catch (NoSuchServiceContext exc) {
  504. // If no code set information is ever sent from the client,
  505. // the server will use ISO8859-1 for char and throw an
  506. // exception for any wchar transmissions.
  507. //
  508. // In the local case, we use ORB provided streams for
  509. // marshaling and unmarshaling. Currently, they use
  510. // ISO8859-1 for char/string and UTF16 for wchar/wstring.
  511. return false;
  512. }
  513. }
  514. }