1 /*
   2  * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * Licensed Materials - Property of IBM
  27  * RMI-IIOP v1.0
  28  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  29  *
  30  */
  31 
  32 
  33 package com.sun.corba.se.impl.protocol;
  34 
  35 import org.omg.PortableServer.Servant ;
  36 
  37 import org.omg.CORBA.SystemException;
  38 import org.omg.CORBA.INTERNAL;
  39 import org.omg.CORBA.UNKNOWN;
  40 import org.omg.CORBA.CompletionStatus;
  41 import org.omg.CORBA.Any;
  42 
  43 import org.omg.CORBA.portable.InvokeHandler;
  44 import org.omg.CORBA.portable.InputStream;
  45 import org.omg.CORBA.portable.OutputStream;
  46 import org.omg.CORBA.portable.UnknownException;
  47 import org.omg.CORBA.portable.ResponseHandler;
  48 
  49 import com.sun.org.omg.SendingContext.CodeBase;
  50 
  51 import com.sun.corba.se.pept.encoding.OutputObject;
  52 import com.sun.corba.se.pept.protocol.MessageMediator;
  53 
  54 import com.sun.corba.se.spi.orb.ORB;
  55 import com.sun.corba.se.spi.orb.ORBVersion;
  56 import com.sun.corba.se.spi.orb.ORBVersionFactory;
  57 import com.sun.corba.se.spi.ior.IOR ;
  58 import com.sun.corba.se.spi.ior.ObjectKey;
  59 import com.sun.corba.se.spi.ior.ObjectKeyTemplate;
  60 import com.sun.corba.se.spi.ior.ObjectAdapterId;
  61 import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
  62 import com.sun.corba.se.spi.oa.ObjectAdapter;
  63 import com.sun.corba.se.spi.oa.OAInvocationInfo;
  64 import com.sun.corba.se.spi.oa.OADestroyed;
  65 import com.sun.corba.se.spi.oa.NullServant;
  66 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  67 import com.sun.corba.se.spi.protocol.CorbaServerRequestDispatcher;
  68 import com.sun.corba.se.spi.protocol.ForwardException ;
  69 import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
  70 import com.sun.corba.se.spi.transport.CorbaConnection;
  71 import com.sun.corba.se.spi.logging.CORBALogDomains;
  72 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  73 
  74 import com.sun.corba.se.impl.protocol.SpecialMethod ;
  75 import com.sun.corba.se.spi.servicecontext.ServiceContext;
  76 import com.sun.corba.se.spi.servicecontext.ServiceContexts;
  77 import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext;
  78 import com.sun.corba.se.spi.servicecontext.CodeSetServiceContext;
  79 import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext;
  80 import com.sun.corba.se.spi.servicecontext.ORBVersionServiceContext;
  81 
  82 import com.sun.corba.se.impl.corba.ServerRequestImpl ;
  83 import com.sun.corba.se.impl.encoding.MarshalInputStream;
  84 import com.sun.corba.se.impl.encoding.MarshalOutputStream;
  85 import com.sun.corba.se.impl.encoding.CodeSetComponentInfo;
  86 import com.sun.corba.se.impl.encoding.OSFCodeSetRegistry;
  87 import com.sun.corba.se.impl.orbutil.ORBConstants;
  88 import com.sun.corba.se.impl.orbutil.ORBUtility;
  89 import com.sun.corba.se.impl.protocol.RequestCanceledException;
  90 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
  91 import com.sun.corba.se.impl.logging.POASystemException;
  92 
  93 public class CorbaServerRequestDispatcherImpl
  94     implements CorbaServerRequestDispatcher
  95 {
  96     protected ORB orb; // my ORB instance
  97     private ORBUtilSystemException wrapper ;
  98     private POASystemException poaWrapper ;
  99 
 100     // Added from last version because it broke the build - RTW
 101     // XXX remove me and rebuild: probably no longer needed
 102     // public static final int UNKNOWN_EXCEPTION_INFO_ID = 9;
 103 
 104     public CorbaServerRequestDispatcherImpl(ORB orb)
 105     {
 106         this.orb = orb;
 107         wrapper = ORBUtilSystemException.get( orb,
 108             CORBALogDomains.RPC_PROTOCOL ) ;
 109         poaWrapper = POASystemException.get( orb,
 110             CORBALogDomains.RPC_PROTOCOL ) ;
 111     }
 112 
 113     /** XXX/REVISIT:
 114      * We do not want to look for a servant in the POA/ServantManager case,
 115      * but we could in most other cases.  The OA could have a method that
 116      * returns true if the servant MAY exist, and false only if the servant
 117      * definitely DOES NOT exist.
 118      *
 119      * XXX/REVISIT:
 120      * We may wish to indicate OBJECT_HERE by some mechanism other than
 121      * returning a null result.
 122      *
 123      * Called from ORB.locate when a LocateRequest arrives.
 124      * Result is not always absolutely correct: may indicate OBJECT_HERE
 125      * for non-existent objects, which is resolved on invocation.  This
 126      * "bug" is unavoidable, since in general the object may be destroyed
 127      * between a locate and a request.  Note that this only checks that
 128      * the appropriate ObjectAdapter is available, not that the servant
 129      * actually exists.
 130      * Need to signal one of OBJECT_HERE, OBJECT_FORWARD, OBJECT_NOT_EXIST.
 131      * @return Result is null if object is (possibly) implemented here, otherwise
 132      * an IOR indicating objref to forward the request to.
 133      * @exception OBJECT_NOT_EXIST is thrown if we know the object does not
 134      * exist here, and we are not forwarding.
 135      */
 136     public IOR locate(ObjectKey okey)
 137     {
 138         try {
 139             if (orb.subcontractDebugFlag)
 140                 dprint(".locate->");
 141 
 142             ObjectKeyTemplate oktemp = okey.getTemplate() ;
 143 
 144             try {
 145                 checkServerId(okey);
 146             } catch (ForwardException fex) {
 147                 return fex.getIOR() ;
 148             }
 149 
 150             // Called only for its side-effect of throwing appropriate exceptions
 151             findObjectAdapter(oktemp);
 152 
 153             return null ;
 154         } finally {
 155             if (orb.subcontractDebugFlag)
 156                 dprint(".locate<-");
 157         }
 158     }
 159 
 160     public void dispatch(MessageMediator messageMediator)
 161     {
 162         CorbaMessageMediator request = (CorbaMessageMediator) messageMediator;
 163         try {
 164             if (orb.subcontractDebugFlag) {
 165                 dprint(".dispatch->: " + opAndId(request));
 166             }
 167 
 168             // to set the codebase information, if any transmitted; and also
 169             // appropriate ORB Version.
 170             consumeServiceContexts(request);
 171 
 172             // Now that we have the service contexts processed and the
 173             // correct ORBVersion set, we must finish initializing the
 174             // stream.
 175             ((MarshalInputStream)request.getInputObject())
 176                 .performORBVersionSpecificInit();
 177 
 178             ObjectKey okey = request.getObjectKey();
 179 
 180             // Check that this server is the right server
 181             try {
 182                 checkServerId(okey);
 183             } catch (ForwardException fex) {
 184                 if (orb.subcontractDebugFlag) {
 185                     dprint(".dispatch: " + opAndId(request)
 186                            + ": bad server id");
 187                 }
 188 
 189                 request.getProtocolHandler()
 190                     .createLocationForward(request, fex.getIOR(), null);
 191                 return;
 192             }
 193 
 194             String operation = request.getOperationName();
 195             ObjectAdapter objectAdapter = null ;
 196 
 197             try {
 198                 byte[] objectId = okey.getId().getId() ;
 199                 ObjectKeyTemplate oktemp = okey.getTemplate() ;
 200                 objectAdapter = findObjectAdapter(oktemp);
 201 
 202                 java.lang.Object servant = getServantWithPI(request, objectAdapter,
 203                     objectId, oktemp, operation);
 204 
 205                 dispatchToServant(servant, request, objectId, objectAdapter);
 206             } catch (ForwardException ex) {
 207                 if (orb.subcontractDebugFlag) {
 208                     dprint(".dispatch: " + opAndId(request)
 209                            + ": ForwardException caught");
 210                 }
 211 
 212                 // Thrown by Portable Interceptors from InterceptorInvoker,
 213                 // through Response constructor.
 214                 request.getProtocolHandler()
 215                     .createLocationForward(request, ex.getIOR(), null);
 216             } catch (OADestroyed ex) {
 217                 if (orb.subcontractDebugFlag) {
 218                     dprint(".dispatch: " + opAndId(request)
 219                            + ": OADestroyed exception caught");
 220                 }
 221 
 222                 // DO NOT CALL THIS HERE:
 223                 // releaseServant(objectAdapter);
 224                 // The problem is that OADestroyed is only thrown by oa.enter, in
 225                 // which case oa.exit should NOT be called, and neither should
 226                 // the invocationInfo stack be popped.
 227 
 228                 // Destroyed POAs can be recreated by normal adapter activation.
 229                 // So just restart the dispatch.
 230                 dispatch(request);
 231             } catch (RequestCanceledException ex) {
 232                 if (orb.subcontractDebugFlag) {
 233                     dprint(".dispatch: " + opAndId(request)
 234                            + ": RequestCanceledException caught");
 235                 }
 236 
 237                 // IDLJ generated non-tie based skeletons do not catch the
 238                 // RequestCanceledException. Rethrow the exception, which will
 239                 // cause the worker thread to unwind the dispatch and wait for
 240                 // other requests.
 241                 throw ex;
 242             } catch (UnknownException ex) {
 243                 if (orb.subcontractDebugFlag) {
 244                     dprint(".dispatch: " + opAndId(request)
 245                            + ": UnknownException caught " + ex);
 246                 }
 247 
 248                 // RMIC generated tie skeletons convert all Throwable exception
 249                 // types (including RequestCanceledException, ThreadDeath)
 250                 // thrown during reading fragments into UnknownException.
 251                 // If RequestCanceledException was indeed raised,
 252                 // then rethrow it, which will eventually cause the worker
 253                 // thread to unstack the dispatch and wait for other requests.
 254                 if (ex.originalEx instanceof RequestCanceledException) {
 255                     throw (RequestCanceledException) ex.originalEx;
 256                 }
 257 
 258                 ServiceContexts contexts = new ServiceContexts(orb);
 259                 UEInfoServiceContext usc = new UEInfoServiceContext(
 260                     ex.originalEx);
 261 
 262                 contexts.put( usc ) ;
 263 
 264                 SystemException sysex = wrapper.unknownExceptionInDispatch(
 265                         CompletionStatus.COMPLETED_MAYBE, ex ) ;
 266                 request.getProtocolHandler()
 267                     .createSystemExceptionResponse(request, sysex,
 268                         contexts);
 269             } catch (Throwable ex) {
 270                 if (orb.subcontractDebugFlag) {
 271                     dprint(".dispatch: " + opAndId(request)
 272                            + ": other exception " + ex);
 273                 }
 274                 request.getProtocolHandler()
 275                     .handleThrowableDuringServerDispatch(
 276                         request, ex, CompletionStatus.COMPLETED_MAYBE);
 277             }
 278             return;
 279         } finally {
 280             if (orb.subcontractDebugFlag) {
 281                 dprint(".dispatch<-: " + opAndId(request));
 282             }
 283         }
 284     }
 285 
 286     private void releaseServant(ObjectAdapter objectAdapter)
 287     {
 288         try {
 289             if (orb.subcontractDebugFlag) {
 290                 dprint(".releaseServant->");
 291             }
 292 
 293             if (objectAdapter == null) {
 294                 if (orb.subcontractDebugFlag) {
 295                     dprint(".releaseServant: null object adapter");
 296                 }
 297                 return ;
 298             }
 299 
 300             try {
 301                 objectAdapter.returnServant();
 302             } finally {
 303                 objectAdapter.exit();
 304                 orb.popInvocationInfo() ;
 305             }
 306         } finally {
 307             if (orb.subcontractDebugFlag) {
 308                 dprint(".releaseServant<-");
 309             }
 310         }
 311     }
 312 
 313     // Note that objectAdapter.enter() must be called before getServant.
 314     private java.lang.Object getServant(ObjectAdapter objectAdapter, byte[] objectId,
 315         String operation)
 316         throws OADestroyed
 317     {
 318         try {
 319             if (orb.subcontractDebugFlag) {
 320                 dprint(".getServant->");
 321             }
 322 
 323             OAInvocationInfo info = objectAdapter.makeInvocationInfo(objectId);
 324             info.setOperation(operation);
 325             orb.pushInvocationInfo(info);
 326             objectAdapter.getInvocationServant(info);
 327             return info.getServantContainer() ;
 328         } finally {
 329             if (orb.subcontractDebugFlag) {
 330                 dprint(".getServant<-");
 331             }
 332         }
 333     }
 334 
 335     protected java.lang.Object getServantWithPI(CorbaMessageMediator request,
 336                                                  ObjectAdapter objectAdapter,
 337         byte[] objectId, ObjectKeyTemplate oktemp, String operation)
 338         throws OADestroyed
 339     {
 340         try {
 341             if (orb.subcontractDebugFlag) {
 342                 dprint(".getServantWithPI->");
 343             }
 344 
 345             // Prepare Portable Interceptors for a new server request
 346             // and invoke receive_request_service_contexts.  The starting
 347             // point may throw a SystemException or ForwardException.
 348             orb.getPIHandler().initializeServerPIInfo(request, objectAdapter,
 349                 objectId, oktemp);
 350             orb.getPIHandler().invokeServerPIStartingPoint();
 351 
 352             objectAdapter.enter() ;
 353 
 354             // This must be set just after the enter so that exceptions thrown by
 355             // enter do not cause
 356             // the exception reply to pop the thread stack and do an extra oa.exit.
 357             if (request != null)
 358                 request.setExecuteReturnServantInResponseConstructor(true);
 359 
 360             java.lang.Object servant = getServant(objectAdapter, objectId,
 361                 operation);
 362 
 363             // Note: we do not know the MDI on a null servant.
 364             // We only end up in that situation if _non_existent called,
 365             // so that the following handleNullServant call does not throw an
 366             // exception.
 367             String mdi = "unknown" ;
 368 
 369             if (servant instanceof NullServant)
 370                 handleNullServant(operation, (NullServant)servant);
 371             else
 372                 mdi = objectAdapter.getInterfaces(servant, objectId)[0] ;
 373 
 374             orb.getPIHandler().setServerPIInfo(servant, mdi);
 375 
 376             if (((servant != null) &&
 377                 !(servant instanceof org.omg.CORBA.DynamicImplementation) &&
 378                 !(servant instanceof org.omg.PortableServer.DynamicImplementation)) ||
 379                 (SpecialMethod.getSpecialMethod(operation) != null)) {
 380                 orb.getPIHandler().invokeServerPIIntermediatePoint();
 381             }
 382 
 383             return servant ;
 384         } finally {
 385             if (orb.subcontractDebugFlag) {
 386                 dprint(".getServantWithPI<-");
 387             }
 388         }
 389     }
 390 
 391     protected void checkServerId(ObjectKey okey)
 392     {
 393         try {
 394             if (orb.subcontractDebugFlag) {
 395                 dprint(".checkServerId->");
 396             }
 397 
 398             ObjectKeyTemplate oktemp = okey.getTemplate() ;
 399             int sId = oktemp.getServerId() ;
 400             int scid = oktemp.getSubcontractId() ;
 401 
 402             if (!orb.isLocalServerId(scid, sId)) {
 403                 if (orb.subcontractDebugFlag) {
 404                     dprint(".checkServerId: bad server id");
 405                 }
 406 
 407                 orb.handleBadServerId(okey);
 408             }
 409         } finally {
 410             if (orb.subcontractDebugFlag) {
 411                 dprint(".checkServerId<-");
 412             }
 413         }
 414     }
 415 
 416     private ObjectAdapter findObjectAdapter(ObjectKeyTemplate oktemp)
 417     {
 418         try {
 419             if (orb.subcontractDebugFlag) {
 420                 dprint(".findObjectAdapter->");
 421             }
 422 
 423             RequestDispatcherRegistry scr = orb.getRequestDispatcherRegistry() ;
 424             int scid = oktemp.getSubcontractId() ;
 425             ObjectAdapterFactory oaf = scr.getObjectAdapterFactory(scid);
 426             if (oaf == null) {
 427                 if (orb.subcontractDebugFlag) {
 428                     dprint(".findObjectAdapter: failed to find ObjectAdapterFactory");
 429                 }
 430 
 431                 throw wrapper.noObjectAdapterFactory() ;
 432             }
 433 
 434             ObjectAdapterId oaid = oktemp.getObjectAdapterId() ;
 435             ObjectAdapter oa = oaf.find(oaid);
 436 
 437             if (oa == null) {
 438                 if (orb.subcontractDebugFlag) {
 439                     dprint(".findObjectAdapter: failed to find ObjectAdaptor");
 440                 }
 441 
 442                 throw wrapper.badAdapterId() ;
 443             }
 444 
 445             return oa ;
 446         } finally {
 447             if (orb.subcontractDebugFlag) {
 448                 dprint(".findObjectAdapter<-");
 449             }
 450         }
 451     }
 452 
 453     /** Always throws OBJECT_NOT_EXIST if operation is not a special method.
 454     * If operation is _non_existent or _not_existent, this will just
 455     * return without performing any action, so that _non_existent can return
 456     * false.  Always throws OBJECT_NOT_EXIST for any other special method.
 457     * Update for issue 4385.
 458     */
 459     protected void handleNullServant(String operation, NullServant nserv )
 460     {
 461         try {
 462             if (orb.subcontractDebugFlag) {
 463                 dprint(".handleNullServant->: " + operation);
 464             }
 465 
 466             SpecialMethod specialMethod =
 467                 SpecialMethod.getSpecialMethod(operation);
 468 
 469             if ((specialMethod == null) ||
 470                 !specialMethod.isNonExistentMethod()) {
 471                 if (orb.subcontractDebugFlag) {
 472                     dprint(".handleNullServant: " + operation
 473                            + ": throwing OBJECT_NOT_EXIST");
 474                 }
 475 
 476                 throw nserv.getException() ;
 477             }
 478         } finally {
 479             if (orb.subcontractDebugFlag) {
 480                 dprint(".handleNullServant<-: " + operation);
 481             }
 482         }
 483     }
 484 
 485     protected void consumeServiceContexts(CorbaMessageMediator request)
 486     {
 487         try {
 488             if (orb.subcontractDebugFlag) {
 489                 dprint(".consumeServiceContexts->: "
 490                        + opAndId(request));
 491             }
 492 
 493             ServiceContexts ctxts = request.getRequestServiceContexts();
 494             ServiceContext sc ;
 495 
 496             GIOPVersion giopVersion = request.getGIOPVersion();
 497 
 498             // we cannot depend on this since for our local case, we do not send
 499             // in this service context.  Can we rely on just the CodeSetServiceContext?
 500             // boolean rtSC = false; // Runtime ServiceContext
 501 
 502             boolean hasCodeSetContext = processCodeSetContext(request, ctxts);
 503 
 504             if (orb.subcontractDebugFlag) {
 505                 dprint(".consumeServiceContexts: " + opAndId(request)
 506                        + ": GIOP version: " + giopVersion);
 507                 dprint(".consumeServiceContexts: " + opAndId(request)
 508                        + ": as code set context? " + hasCodeSetContext);
 509             }
 510 
 511             sc = ctxts.get(
 512                 SendingContextServiceContext.SERVICE_CONTEXT_ID ) ;
 513 
 514             if (sc != null) {
 515                 SendingContextServiceContext scsc =
 516                     (SendingContextServiceContext)sc ;
 517                 IOR ior = scsc.getIOR() ;
 518 
 519                 try {
 520                     ((CorbaConnection)request.getConnection())
 521                         .setCodeBaseIOR(ior);
 522                 } catch (ThreadDeath td) {
 523                     throw td ;
 524                 } catch (Throwable t) {
 525                     throw wrapper.badStringifiedIor( t ) ;
 526                 }
 527             }
 528 
 529             // the RTSC is sent only once during session establishment.  We
 530             // need to find out if the CodeBaseRef is already set.  If yes,
 531             // then also the rtSC flag needs to be set to true
 532             // this is not possible for the LocalCase since there is no
 533             // IIOPConnection for the LocalCase
 534 
 535             // used for a case where we have JDK 1.3 supporting 1.0 protocol,
 536             // but sending 2 service contexts, that is not normal as per
 537             // GIOP rules, based on above information, we figure out that we
 538             // are talking to the legacy ORB and set the ORB Version Accordingly.
 539 
 540             // this special case tell us that it is legacy SUN orb
 541             // and not a foreign one
 542             // rtSC is not available for localcase due to which this generic
 543             // path would fail if relying on rtSC
 544             //if (giopVersion.equals(GIOPVersion.V1_0) && hasCodeSetContext && rtSC)
 545             boolean isForeignORB = false;
 546 
 547             if (giopVersion.equals(GIOPVersion.V1_0) && hasCodeSetContext) {
 548                 if (orb.subcontractDebugFlag) {
 549                     dprint(".consumeServiceCOntexts: " + opAndId(request)
 550                            + ": Determined to be an old Sun ORB");
 551                 }
 552 
 553                 orb.setORBVersion(ORBVersionFactory.getOLD()) ;
 554                 // System.out.println("setting legacy ORB version");
 555             } else {
 556                 // If it didn't include our ORB version service context (below),
 557                 // then it must be a foreign ORB.
 558                 isForeignORB = true;
 559             }
 560 
 561             // try to get the ORBVersion sent as part of the ServiceContext
 562             // if any
 563             sc = ctxts.get( ORBVersionServiceContext.SERVICE_CONTEXT_ID ) ;
 564             if (sc != null) {
 565                 ORBVersionServiceContext ovsc =
 566                    (ORBVersionServiceContext) sc;
 567 
 568                 ORBVersion version = ovsc.getVersion();
 569                 orb.setORBVersion(version);
 570 
 571                 isForeignORB = false;
 572             }
 573 
 574             if (isForeignORB) {
 575                 if (orb.subcontractDebugFlag) {
 576                     dprint(".consumeServiceContexts: " + opAndId(request)
 577                            + ": Determined to be a foreign ORB");
 578                 }
 579 
 580                 orb.setORBVersion(ORBVersionFactory.getFOREIGN());
 581             }
 582         } finally {
 583             if (orb.subcontractDebugFlag) {
 584                 dprint(".consumeServiceContexts<-: " + opAndId(request));
 585             }
 586         }
 587     }
 588 
 589     protected CorbaMessageMediator dispatchToServant(
 590         java.lang.Object servant,
 591         CorbaMessageMediator req,
 592         byte[] objectId, ObjectAdapter objectAdapter)
 593     {
 594         try {
 595             if (orb.subcontractDebugFlag) {
 596                 dprint(".dispatchToServant->: " + opAndId(req));
 597             }
 598 
 599             CorbaMessageMediator response = null ;
 600 
 601             String operation = req.getOperationName() ;
 602 
 603             SpecialMethod method = SpecialMethod.getSpecialMethod(operation) ;
 604             if (method != null) {
 605                 if (orb.subcontractDebugFlag) {
 606                     dprint(".dispatchToServant: " + opAndId(req)
 607                            + ": Handling special method");
 608                 }
 609 
 610                 response = method.invoke(servant, req, objectId, objectAdapter);
 611                 return response ;
 612             }
 613 
 614             // Invoke on the servant using the portable DSI skeleton
 615             if (servant instanceof org.omg.CORBA.DynamicImplementation) {
 616                 if (orb.subcontractDebugFlag) {
 617                     dprint(".dispatchToServant: " + opAndId(req)
 618                            + ": Handling old style DSI type servant");
 619                 }
 620 
 621                 org.omg.CORBA.DynamicImplementation dynimpl =
 622                     (org.omg.CORBA.DynamicImplementation)servant;
 623                 ServerRequestImpl sreq = new ServerRequestImpl(req, orb);
 624 
 625                 // Note: When/if dynimpl.invoke calls arguments() or
 626                 // set_exception() then intermediate points are run.
 627                 dynimpl.invoke(sreq);
 628 
 629                 response = handleDynamicResult(sreq, req);
 630             } else if (servant instanceof org.omg.PortableServer.DynamicImplementation) {
 631                 if (orb.subcontractDebugFlag) {
 632                     dprint(".dispatchToServant: " + opAndId(req)
 633                            + ": Handling POA DSI type servant");
 634                 }
 635 
 636                 org.omg.PortableServer.DynamicImplementation dynimpl =
 637                     (org.omg.PortableServer.DynamicImplementation)servant;
 638                 ServerRequestImpl sreq = new ServerRequestImpl(req, orb);
 639 
 640                 // Note: When/if dynimpl.invoke calls arguments() or
 641                 // set_exception() then intermediate points are run.
 642                 dynimpl.invoke(sreq);
 643 
 644                 response = handleDynamicResult(sreq, req);
 645             } else {
 646                 if (orb.subcontractDebugFlag) {
 647                     dprint(".dispatchToServant: " + opAndId(req)
 648                            + ": Handling invoke handler type servant");
 649                 }
 650 
 651                 InvokeHandler invhandle = (InvokeHandler)servant ;
 652 
 653                 OutputStream stream =
 654                     (OutputStream)invhandle._invoke(
 655                       operation,
 656                       (org.omg.CORBA.portable.InputStream)req.getInputObject(),
 657                       req);
 658                 response = (CorbaMessageMediator)
 659                     ((OutputObject)stream).getMessageMediator();
 660             }
 661 
 662             return response ;
 663         } finally {
 664             if (orb.subcontractDebugFlag) {
 665                 dprint(".dispatchToServant<-: " + opAndId(req));
 666             }
 667         }
 668     }
 669 
 670     protected CorbaMessageMediator handleDynamicResult(
 671         ServerRequestImpl sreq,
 672         CorbaMessageMediator req)
 673     {
 674         try {
 675             if (orb.subcontractDebugFlag) {
 676                 dprint(".handleDynamicResult->: " + opAndId(req));
 677             }
 678 
 679             CorbaMessageMediator response = null ;
 680 
 681             // Check if ServerRequestImpl.result() has been called
 682             Any excany = sreq.checkResultCalled();
 683 
 684             if (excany == null) { // normal return
 685                 if (orb.subcontractDebugFlag) {
 686                     dprint(".handleDynamicResult: " + opAndId(req)
 687                            + ": handling normal result");
 688                 }
 689 
 690                 // Marshal out/inout/return parameters into the ReplyMessage
 691                 response = sendingReply(req);
 692                 OutputStream os = (OutputStream) response.getOutputObject();
 693                 sreq.marshalReplyParams(os);
 694             }  else {
 695                 if (orb.subcontractDebugFlag) {
 696                     dprint(".handleDynamicResult: " + opAndId(req)
 697                            + ": handling error");
 698                 }
 699 
 700                 response = sendingReply(req, excany);
 701             }
 702 
 703             return response ;
 704         } finally {
 705             if (orb.subcontractDebugFlag) {
 706                 dprint(".handleDynamicResult<-: " + opAndId(req));
 707             }
 708         }
 709     }
 710 
 711     protected CorbaMessageMediator sendingReply(CorbaMessageMediator req)
 712     {
 713         try {
 714             if (orb.subcontractDebugFlag) {
 715                 dprint(".sendingReply->: " + opAndId(req));
 716             }
 717 
 718             ServiceContexts scs = new ServiceContexts(orb);
 719             return req.getProtocolHandler().createResponse(req, scs);
 720         } finally {
 721             if (orb.subcontractDebugFlag) {
 722                 dprint(".sendingReply<-: " + opAndId(req));
 723             }
 724         }
 725     }
 726 
 727     /** Must always be called, just after the servant's method returns.
 728      *  Creates the ReplyMessage header and puts in the transaction context
 729      *  if necessary.
 730      */
 731     protected CorbaMessageMediator sendingReply(CorbaMessageMediator req, Any excany)
 732     {
 733         try {
 734             if (orb.subcontractDebugFlag) {
 735                 dprint(".sendingReply/Any->: " + opAndId(req));
 736             }
 737 
 738             ServiceContexts scs = new ServiceContexts(orb);
 739 
 740             // Check if the servant set a SystemException or
 741             // UserException
 742             CorbaMessageMediator resp;
 743             String repId=null;
 744             try {
 745                 repId = excany.type().id();
 746             } catch (org.omg.CORBA.TypeCodePackage.BadKind e) {
 747                 throw wrapper.problemWithExceptionTypecode( e ) ;
 748             }
 749 
 750             if (ORBUtility.isSystemException(repId)) {
 751                 if (orb.subcontractDebugFlag) {
 752                     dprint(".sendingReply/Any: " + opAndId(req)
 753                            + ": handling system exception");
 754                 }
 755 
 756                 // Get the exception object from the Any
 757                 InputStream in = excany.create_input_stream();
 758                 SystemException ex = ORBUtility.readSystemException(in);
 759                 // Marshal the exception back
 760                 resp = req.getProtocolHandler()
 761                     .createSystemExceptionResponse(req, ex, scs);
 762             } else {
 763                 if (orb.subcontractDebugFlag) {
 764                     dprint(".sendingReply/Any: " + opAndId(req)
 765                            + ": handling user exception");
 766                 }
 767 
 768                 resp = req.getProtocolHandler()
 769                     .createUserExceptionResponse(req, scs);
 770                 OutputStream os = (OutputStream)resp.getOutputObject();
 771                 excany.write_value(os);
 772             }
 773 
 774             return resp;
 775         } finally {
 776             if (orb.subcontractDebugFlag) {
 777                 dprint(".sendingReply/Any<-: " + opAndId(req));
 778             }
 779         }
 780     }
 781 
 782     /**
 783      * Handles setting the connection's code sets if required.
 784      * Returns true if the CodeSetContext was in the request, false
 785      * otherwise.
 786      */
 787     protected boolean processCodeSetContext(
 788         CorbaMessageMediator request, ServiceContexts contexts)
 789     {
 790         try {
 791             if (orb.subcontractDebugFlag) {
 792                 dprint(".processCodeSetContext->: " + opAndId(request));
 793             }
 794 
 795             ServiceContext sc = contexts.get(
 796                 CodeSetServiceContext.SERVICE_CONTEXT_ID);
 797             if (sc != null) {
 798                 // Somehow a code set service context showed up in the local case.
 799                 if (request.getConnection() == null) {
 800                     return true;
 801                 }
 802 
 803                 // If it's GIOP 1.0, it shouldn't have this context at all.  Our legacy
 804                 // ORBs sent it and we need to know if it's here to make ORB versioning
 805                 // decisions, but we don't use the contents.
 806                 if (request.getGIOPVersion().equals(GIOPVersion.V1_0)) {
 807                     return true;
 808                 }
 809 
 810                 CodeSetServiceContext cssc = (CodeSetServiceContext)sc ;
 811                 CodeSetComponentInfo.CodeSetContext csctx = cssc.getCodeSetContext();
 812 
 813                 // Note on threading:
 814                 //
 815                 // getCodeSetContext and setCodeSetContext are synchronized
 816                 // on the Connection.  At worst, this will result in
 817                 // multiple threads entering this block and calling
 818                 // setCodeSetContext but not actually changing the
 819                 // values on the Connection.
 820                 //
 821                 // Alternative would be to lock the connection for the
 822                 // whole block, but it's fine either way.
 823 
 824                 // The connection's codeSetContext is null until we've received a
 825                 // request with a code set context with the negotiated code sets.
 826                 if (((CorbaConnection)request.getConnection())
 827                     .getCodeSetContext() == null)
 828                 {
 829 
 830                     // Use these code sets on this connection
 831                     if (orb.subcontractDebugFlag) {
 832                         dprint(".processCodeSetContext: " + opAndId(request)
 833                                + ": Setting code sets to: " + csctx);
 834                     }
 835 
 836                     ((CorbaConnection)request.getConnection())
 837                         .setCodeSetContext(csctx);
 838 
 839                     // We had to read the method name using ISO 8859-1
 840                     // (which is the default in the CDRInputStream for
 841                     // char data), but now we may have a new char
 842                     // code set.  If it isn't ISO8859-1, we must tell
 843                     // the CDR stream to null any converter references
 844                     // it has created so that it will reacquire
 845                     // the code sets again using the new info.
 846                     //
 847                     // This should probably compare with the stream's
 848                     // char code set rather than assuming it's ISO8859-1.
 849                     // (However, the operation name is almost certainly
 850                     // ISO8859-1 or ASCII.)
 851                     if (csctx.getCharCodeSet() !=
 852                         OSFCodeSetRegistry.ISO_8859_1.getNumber()) {
 853                         ((MarshalInputStream)request.getInputObject())
 854                             .resetCodeSetConverters();
 855                     }
 856                 }
 857             }
 858 
 859             // If no code set information is ever sent from the client,
 860             // the server will use ISO8859-1 for char and throw an
 861             // exception for any wchar transmissions.
 862             //
 863             // In the local case, we use ORB provided streams for
 864             // marshaling and unmarshaling.  Currently, they use
 865             // ISO8859-1 for char/string and UTF16 for wchar/wstring.
 866             return sc != null ;
 867         } finally {
 868             if (orb.subcontractDebugFlag) {
 869                 dprint(".processCodeSetContext<-: " + opAndId(request));
 870             }
 871         }
 872     }
 873 
 874     protected void dprint(String msg)
 875     {
 876         ORBUtility.dprint("CorbaServerRequestDispatcherImpl", msg);
 877     }
 878 
 879     protected String opAndId(CorbaMessageMediator mediator)
 880     {
 881         return ORBUtility.operationNameAndRequestId(mediator);
 882     }
 883 }
 884 
 885 // End of file.