1 /*
   2  * Copyright (c) 2001, 2013, 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 /*
  27  * Licensed Materials - Property of IBM
  28  * RMI-IIOP v1.0
  29  * Copyright IBM Corp. 1998 1999  All Rights Reserved
  30  *
  31  */
  32 
  33 package com.sun.corba.se.impl.protocol;
  34 
  35 import java.io.IOException;
  36 import java.util.Iterator;
  37 import java.rmi.RemoteException;
  38 
  39 import javax.rmi.CORBA.Util;
  40 import javax.rmi.CORBA.Tie;
  41 
  42 import org.omg.CORBA.COMM_FAILURE;
  43 import org.omg.CORBA.INTERNAL;
  44 import org.omg.CORBA.SystemException;
  45 import org.omg.CORBA.Request;
  46 import org.omg.CORBA.NamedValue;
  47 import org.omg.CORBA.NVList;
  48 import org.omg.CORBA.Context;
  49 import org.omg.CORBA.ContextList;
  50 import org.omg.CORBA.ExceptionList;
  51 import org.omg.CORBA.TypeCode;
  52 import org.omg.CORBA.portable.RemarshalException;
  53 import org.omg.CORBA_2_3.portable.InputStream;
  54 import org.omg.CORBA_2_3.portable.OutputStream;
  55 import org.omg.CORBA.portable.Delegate;
  56 import org.omg.CORBA.portable.ServantObject;
  57 import org.omg.CORBA.portable.ApplicationException;
  58 import org.omg.CORBA.portable.UnknownException;
  59 import org.omg.IOP.ExceptionDetailMessage;
  60 import org.omg.IOP.TAG_CODE_SETS;
  61 
  62 import com.sun.org.omg.SendingContext.CodeBase;
  63 
  64 import com.sun.corba.se.pept.broker.Broker;
  65 import com.sun.corba.se.pept.encoding.InputObject;
  66 import com.sun.corba.se.pept.encoding.OutputObject;
  67 import com.sun.corba.se.pept.protocol.ClientRequestDispatcher;
  68 import com.sun.corba.se.pept.protocol.MessageMediator;
  69 import com.sun.corba.se.pept.transport.Connection;
  70 import com.sun.corba.se.pept.transport.OutboundConnectionCache;
  71 import com.sun.corba.se.pept.transport.ContactInfo;
  72 
  73 import com.sun.corba.se.spi.ior.IOR;
  74 import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  75 import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate;
  76 import com.sun.corba.se.spi.ior.iiop.CodeSetsComponent;
  77 import com.sun.corba.se.spi.oa.OAInvocationInfo;
  78 import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
  79 import com.sun.corba.se.spi.orb.ORB;
  80 import com.sun.corba.se.spi.orb.ORBVersion;
  81 import com.sun.corba.se.spi.orb.ORBVersionFactory;
  82 import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
  83 import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
  84 import com.sun.corba.se.spi.transport.CorbaContactInfo ;
  85 import com.sun.corba.se.spi.transport.CorbaContactInfoList ;
  86 import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator ;
  87 import com.sun.corba.se.spi.transport.CorbaConnection;
  88 import com.sun.corba.se.spi.logging.CORBALogDomains;
  89 
  90 import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext;
  91 import com.sun.corba.se.spi.servicecontext.ServiceContext;
  92 import com.sun.corba.se.spi.servicecontext.ServiceContexts;
  93 import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext;
  94 import com.sun.corba.se.spi.servicecontext.CodeSetServiceContext;
  95 import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext;
  96 import com.sun.corba.se.spi.servicecontext.ORBVersionServiceContext;
  97 import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext;
  98 import com.sun.corba.se.spi.servicecontext.UnknownServiceContext;
  99 
 100 import com.sun.corba.se.impl.encoding.CDRInputObject;
 101 import com.sun.corba.se.impl.encoding.CodeSetComponentInfo;
 102 import com.sun.corba.se.impl.encoding.CodeSetConversion;
 103 import com.sun.corba.se.impl.encoding.EncapsInputStream;
 104 import com.sun.corba.se.impl.encoding.MarshalOutputStream;
 105 import com.sun.corba.se.impl.encoding.MarshalInputStream;
 106 import com.sun.corba.se.impl.logging.ORBUtilSystemException;
 107 import com.sun.corba.se.impl.orbutil.ORBUtility;
 108 import com.sun.corba.se.impl.orbutil.ORBConstants;
 109 import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage;
 110 import com.sun.corba.se.impl.protocol.giopmsgheaders.KeyAddr;
 111 import com.sun.corba.se.impl.protocol.giopmsgheaders.ProfileAddr;
 112 import com.sun.corba.se.impl.protocol.giopmsgheaders.ReferenceAddr;
 113 import com.sun.corba.se.impl.transport.CorbaContactInfoListIteratorImpl;
 114 import com.sun.corba.se.impl.util.JDKBridge;
 115 
 116 import java.util.concurrent.ConcurrentMap;
 117 import java.util.concurrent.ConcurrentHashMap;
 118 import sun.corba.EncapsInputStreamFactory;
 119 
 120 /**
 121  * ClientDelegate is the RMI client-side subcontract or representation
 122  * It implements RMI delegate as well as our internal ClientRequestDispatcher
 123  * interface.
 124  */
 125 public class CorbaClientRequestDispatcherImpl
 126     implements
 127         ClientRequestDispatcher
 128 {
 129     private ConcurrentMap<ContactInfo, Object> locks =
 130             new ConcurrentHashMap<ContactInfo, Object>();
 131 
 132     public OutputObject beginRequest(Object self, String opName,
 133                                      boolean isOneWay, ContactInfo contactInfo)
 134     {
 135       ORB orb = null;
 136       try {
 137         CorbaContactInfo corbaContactInfo = (CorbaContactInfo) contactInfo;
 138         orb =  (ORB)contactInfo.getBroker();
 139 
 140         if (orb.subcontractDebugFlag) {
 141             dprint(".beginRequest->: op/" + opName);
 142         }
 143 
 144         //
 145         // Portable Interceptor initialization.
 146         //
 147 
 148         orb.getPIHandler().initiateClientPIRequest( false );
 149 
 150         //
 151         // Connection.
 152         //
 153 
 154         CorbaConnection connection = null;
 155 
 156         // This locking is done so that multiple connections are not created
 157         // for the same endpoint
 158         // 7046238 - Synchronization on a single monitor for contactInfo parameters
 159         // with identical hashCode(), so we lock on same monitor for equal parameters
 160         // (which can refer to equal (in terms of equals()) but not the same objects)
 161 
 162         Object lock = locks.get(contactInfo);
 163 
 164         if (lock == null) {
 165             Object newLock = new Object();
 166             lock = locks.putIfAbsent(contactInfo, newLock);
 167             if (lock == null) {
 168                 lock = newLock;
 169             }
 170         }
 171 
 172         synchronized (lock) {
 173             if (contactInfo.isConnectionBased()) {
 174                 if (contactInfo.shouldCacheConnection()) {
 175                     connection = (CorbaConnection)
 176                         orb.getTransportManager()
 177                         .getOutboundConnectionCache(contactInfo).get(contactInfo);
 178                 }
 179                 if (connection != null) {
 180                     if (orb.subcontractDebugFlag) {
 181                         dprint(".beginRequest: op/" + opName
 182                                + ": Using cached connection: " + connection);
 183                     }
 184                 } else {
 185                     try {
 186                         connection = (CorbaConnection)
 187                             contactInfo.createConnection();
 188                         if (orb.subcontractDebugFlag) {
 189                             dprint(".beginRequest: op/" + opName
 190                                    + ": Using created connection: " + connection);
 191                         }
 192                     } catch (RuntimeException e) {
 193                         if (orb.subcontractDebugFlag) {
 194                             dprint(".beginRequest: op/" + opName
 195                                    + ": failed to create connection: " + e);
 196                         }
 197                         // REVISIT: this part similar to marshalingComplete below.
 198                         boolean retry = getContactInfoListIterator(orb)
 199                                            .reportException(contactInfo, e);
 200                         // REVISIT:
 201                         // this part similar to Remarshal in this method below
 202                         if (retry) {
 203                             if(getContactInfoListIterator(orb).hasNext()) {
 204                                 contactInfo = (ContactInfo)
 205                                    getContactInfoListIterator(orb).next();
 206                                 unregisterWaiter(orb);
 207                                 return beginRequest(self, opName,
 208                                                     isOneWay, contactInfo);
 209                             } else {
 210                                 throw e;
 211                             }
 212                         } else {
 213                             throw e;
 214                         }
 215                     }
 216                     if (connection.shouldRegisterReadEvent()) {
 217                         // REVISIT: cast
 218                         orb.getTransportManager().getSelector(0)
 219                             .registerForEvent(connection.getEventHandler());
 220                         connection.setState("ESTABLISHED");
 221                     }
 222                     // Do not do connection reclaim here since the connections
 223                     // are marked in use by registerWaiter() call and since this
 224                     // call happens later do it after that.
 225                     if (contactInfo.shouldCacheConnection()) {
 226                         OutboundConnectionCache connectionCache =
 227                          orb.getTransportManager()
 228                             .getOutboundConnectionCache(contactInfo);
 229                         connectionCache.stampTime(connection);
 230                         connectionCache.put(contactInfo, connection);
 231     //              connectionCache.reclaim();
 232                     }
 233                 }
 234             }
 235         }
 236 
 237         CorbaMessageMediator messageMediator = (CorbaMessageMediator)
 238             contactInfo.createMessageMediator(
 239                 orb, contactInfo, connection, opName, isOneWay);
 240         if (orb.subcontractDebugFlag) {
 241             dprint(".beginRequest: " + opAndId(messageMediator)
 242                    + ": created message mediator: " +  messageMediator);
 243         }
 244 
 245         // NOTE: Thread data so we can get the mediator in release reply
 246         // in order to remove the waiter in CorbaConnection.
 247         // We cannot depend on obtaining information in releaseReply
 248         // via its InputStream argument since, on certain errors
 249         // (e.g., client marshaling errors), the stream may be null.
 250         // Likewise for releaseReply "self".
 251         // NOTE: This must be done before initializing the message since
 252         // that may start sending fragments which may end up in "early"
 253         // replies or client marshaling exceptions.
 254 
 255         orb.getInvocationInfo().setMessageMediator(messageMediator);
 256 
 257         if (connection != null && connection.getCodeSetContext() == null) {
 258             performCodeSetNegotiation(messageMediator);
 259         }
 260 
 261         addServiceContexts(messageMediator);
 262 
 263         OutputObject outputObject =
 264             contactInfo.createOutputObject(messageMediator);
 265         if (orb.subcontractDebugFlag) {
 266             dprint(".beginRequest: " + opAndId(messageMediator)
 267                    + ": created output object: " + outputObject);
 268         }
 269 
 270 
 271         // NOTE: Not necessary for oneways, but useful for debugging.
 272         // This must be done BEFORE message initialization since fragments
 273         // may be sent at that time.
 274         registerWaiter(messageMediator);
 275 
 276         // Do connection reclaim now
 277         synchronized (lock) {
 278             if (contactInfo.isConnectionBased()) {
 279                 if (contactInfo.shouldCacheConnection()) {
 280                     OutboundConnectionCache connectionCache =
 281                              orb.getTransportManager()
 282                                 .getOutboundConnectionCache(contactInfo);
 283                     connectionCache.reclaim();
 284                 }
 285             }
 286         }
 287 
 288         orb.getPIHandler().setClientPIInfo(messageMediator);
 289         try {
 290             // This MUST come before message is initialized so
 291             // service contexts may be added by PI because
 292             // initial fragments may be sent during message initialization.
 293             orb.getPIHandler().invokeClientPIStartingPoint();
 294         } catch( RemarshalException e ) {
 295             if (orb.subcontractDebugFlag) {
 296                 dprint(".beginRequest: " + opAndId(messageMediator)
 297                        + ": Remarshal");
 298             }
 299 
 300             // NOTE: We get here because an interceptor raised ForwardRequest
 301             // and updated the IOR/Iterator.  Since we have a fresh iterator
 302             // hasNext should succeed.
 303 
 304             // REVISIT: We should feed ALL interceptor exceptions to
 305             // iterator.reportException so it can determine if it wants
 306             // to retry.  Right now, SystemExceptions will flow to the
 307             // client code.
 308 
 309             // REVISIT:
 310             // This assumes that interceptors update
 311             // ContactInfoList outside of subcontract.
 312             // Want to move that update to here.
 313             if (getContactInfoListIterator(orb).hasNext()) {
 314                 contactInfo = (ContactInfo)getContactInfoListIterator(orb).next();
 315                 if (orb.subcontractDebugFlag) {
 316                     dprint( "RemarshalException: hasNext true\ncontact info " + contactInfo );
 317                 }
 318 
 319                 // Fix for 6763340: Complete the first attempt before starting another.
 320                 orb.getPIHandler().makeCompletedClientRequest(
 321                     ReplyMessage.LOCATION_FORWARD, null ) ;
 322                 unregisterWaiter(orb);
 323                 orb.getPIHandler().cleanupClientPIRequest() ;
 324 
 325                 return beginRequest(self, opName, isOneWay, contactInfo);
 326             } else {
 327                 if (orb.subcontractDebugFlag) {
 328                     dprint( "RemarshalException: hasNext false" );
 329                 }
 330                 ORBUtilSystemException wrapper =
 331                     ORBUtilSystemException.get(orb,
 332                                                CORBALogDomains.RPC_PROTOCOL);
 333                 throw wrapper.remarshalWithNowhereToGo();
 334             }
 335         }
 336 
 337         messageMediator.initializeMessage();
 338         if (orb.subcontractDebugFlag) {
 339             dprint(".beginRequest: " + opAndId(messageMediator)
 340                    + ": initialized message");
 341         }
 342 
 343         return outputObject;
 344 
 345       } finally {
 346         if (orb.subcontractDebugFlag) {
 347             dprint(".beginRequest<-: op/" + opName);
 348         }
 349       }
 350     }
 351 
 352     public InputObject marshalingComplete(java.lang.Object self,
 353                                           OutputObject outputObject)
 354         throws
 355             ApplicationException,
 356             org.omg.CORBA.portable.RemarshalException
 357     {
 358         ORB orb = null;
 359         CorbaMessageMediator messageMediator = null;
 360         try {
 361             messageMediator = (CorbaMessageMediator)
 362                 outputObject.getMessageMediator();
 363 
 364             orb = (ORB) messageMediator.getBroker();
 365 
 366             if (orb.subcontractDebugFlag) {
 367                 dprint(".marshalingComplete->: " + opAndId(messageMediator));
 368             }
 369 
 370             InputObject inputObject =
 371                 marshalingComplete1(orb, messageMediator);
 372 
 373             return processResponse(orb, messageMediator, inputObject);
 374 
 375         } finally {
 376             if (orb.subcontractDebugFlag) {
 377                 dprint(".marshalingComplete<-: " + opAndId(messageMediator));
 378             }
 379         }
 380     }
 381 
 382     public InputObject marshalingComplete1(
 383             ORB orb, CorbaMessageMediator messageMediator)
 384         throws
 385             ApplicationException,
 386             org.omg.CORBA.portable.RemarshalException
 387     {
 388         try {
 389             messageMediator.finishSendingRequest();
 390 
 391             if (orb.subcontractDebugFlag) {
 392                 dprint(".marshalingComplete: " + opAndId(messageMediator)
 393                        + ": finished sending request");
 394             }
 395 
 396             return messageMediator.waitForResponse();
 397 
 398         } catch (RuntimeException e) {
 399 
 400             if (orb.subcontractDebugFlag) {
 401                 dprint(".marshalingComplete: " + opAndId(messageMediator)
 402                        + ": exception: " + e.toString());
 403             }
 404 
 405             boolean retry  =
 406                 getContactInfoListIterator(orb)
 407                     .reportException(messageMediator.getContactInfo(), e);
 408 
 409             //Bug 6382377: must not lose exception in PI
 410 
 411             // Must run interceptor end point before retrying.
 412             Exception newException =
 413                     orb.getPIHandler().invokeClientPIEndingPoint(
 414                     ReplyMessage.SYSTEM_EXCEPTION, e);
 415 
 416             if (retry) {
 417                 if (newException == e) {
 418                     continueOrThrowSystemOrRemarshal(messageMediator,
 419                                                      new RemarshalException());
 420                 } else {
 421                     continueOrThrowSystemOrRemarshal(messageMediator,
 422                                                      newException);
 423                 }
 424             } else {
 425                 if (newException instanceof RuntimeException){
 426                     throw (RuntimeException)newException;
 427                 }
 428                 else if (newException instanceof RemarshalException)
 429                 {
 430                     throw (RemarshalException)newException;
 431                 }
 432 
 433                 // NOTE: Interceptor ending point will run in releaseReply.
 434                 throw e;
 435             }
 436             return null; // for compiler
 437         }
 438     }
 439 
 440     protected InputObject processResponse(ORB orb,
 441                                           CorbaMessageMediator messageMediator,
 442                                           InputObject inputObject)
 443         throws
 444             ApplicationException,
 445             org.omg.CORBA.portable.RemarshalException
 446     {
 447         ORBUtilSystemException wrapper =
 448             ORBUtilSystemException.get( orb,
 449                 CORBALogDomains.RPC_PROTOCOL ) ;
 450 
 451         if (orb.subcontractDebugFlag) {
 452             dprint(".processResponse: " + opAndId(messageMediator)
 453                    + ": response received");
 454         }
 455 
 456         // We know for sure now that we've sent a message.
 457         // So OK to not send initial again.
 458         if (messageMediator.getConnection() != null) {
 459             ((CorbaConnection)messageMediator.getConnection())
 460                 .setPostInitialContexts();
 461         }
 462 
 463         // NOTE: not necessary to set MessageMediator for PI.
 464         // It already has it.
 465 
 466         // Process the response.
 467 
 468         Exception exception = null;
 469 
 470         if (messageMediator.isOneWay()) {
 471             getContactInfoListIterator(orb)
 472                 .reportSuccess(messageMediator.getContactInfo());
 473             // Invoke Portable Interceptors with receive_other
 474             exception = orb.getPIHandler().invokeClientPIEndingPoint(
 475                 ReplyMessage.NO_EXCEPTION, exception );
 476             continueOrThrowSystemOrRemarshal(messageMediator, exception);
 477             return null;
 478         }
 479 
 480         consumeServiceContexts(orb, messageMediator);
 481 
 482         // Now that we have the service contexts processed and the
 483         // correct ORBVersion set, we must finish initializing the stream.
 484         // REVISIT - need interface for this operation.
 485         ((CDRInputObject)inputObject).performORBVersionSpecificInit();
 486 
 487         if (messageMediator.isSystemExceptionReply()) {
 488 
 489             SystemException se = messageMediator.getSystemExceptionReply();
 490 
 491             if (orb.subcontractDebugFlag) {
 492                 dprint(".processResponse: " + opAndId(messageMediator)
 493                        + ": received system exception: " + se);
 494             }
 495 
 496             boolean doRemarshal =
 497                 getContactInfoListIterator(orb)
 498                     .reportException(messageMediator.getContactInfo(), se);
 499 
 500             if (doRemarshal) {
 501 
 502                 // Invoke Portable Interceptors with receive_exception:
 503                 exception = orb.getPIHandler().invokeClientPIEndingPoint(
 504                     ReplyMessage.SYSTEM_EXCEPTION, se );
 505 
 506                 // If PI did not change the exception, throw a
 507                 // Remarshal.
 508                 if( se == exception ) {
 509                     // exception = null is to maintain symmetry with
 510                     // GenericPOAClientSC.
 511                     exception = null;
 512                     continueOrThrowSystemOrRemarshal(messageMediator,
 513                                                      new RemarshalException());
 514                     throw wrapper.statementNotReachable1() ;
 515                 } else {
 516                     //  Otherwise, throw the exception PI wants thrown.
 517                     continueOrThrowSystemOrRemarshal(messageMediator,
 518                                                      exception);
 519                     throw wrapper.statementNotReachable2() ;
 520                 }
 521             }
 522 
 523             // No retry, so see if was unknown.
 524 
 525             ServiceContexts contexts =
 526                 messageMediator.getReplyServiceContexts();
 527             if (contexts != null) {
 528                 UEInfoServiceContext usc =
 529                     (UEInfoServiceContext)
 530                     contexts.get(UEInfoServiceContext.SERVICE_CONTEXT_ID);
 531 
 532                 if (usc != null) {
 533                     Throwable unknown = usc.getUE() ;
 534                     UnknownException ue = new UnknownException(unknown);
 535 
 536                     // Invoke Portable Interceptors with receive_exception:
 537                     exception = orb.getPIHandler().invokeClientPIEndingPoint(
 538                         ReplyMessage.SYSTEM_EXCEPTION, ue );
 539 
 540                     continueOrThrowSystemOrRemarshal(messageMediator, exception);
 541                     throw wrapper.statementNotReachable3() ;
 542                 }
 543             }
 544 
 545             // It was not a comm failure nor unknown.
 546             // This is the general case.
 547 
 548             // Invoke Portable Interceptors with receive_exception:
 549             exception = orb.getPIHandler().invokeClientPIEndingPoint(
 550                 ReplyMessage.SYSTEM_EXCEPTION, se );
 551 
 552             continueOrThrowSystemOrRemarshal(messageMediator, exception);
 553 
 554             // Note: We should never need to execute this line, but
 555             // we should assert in case exception is null somehow.
 556             throw wrapper.statementNotReachable4() ;
 557         } else if (messageMediator.isUserExceptionReply()) {
 558 
 559             if (orb.subcontractDebugFlag) {
 560                 dprint(".processResponse: " + opAndId(messageMediator)
 561                        + ": received user exception");
 562             }
 563 
 564             getContactInfoListIterator(orb)
 565                 .reportSuccess(messageMediator.getContactInfo());
 566 
 567             String exceptionRepoId = peekUserExceptionId(inputObject);
 568             Exception newException = null;
 569 
 570             if (messageMediator.isDIIRequest()) {
 571                 exception = messageMediator.unmarshalDIIUserException(
 572                                 exceptionRepoId, (InputStream)inputObject);
 573                 newException = orb.getPIHandler().invokeClientPIEndingPoint(
 574                                    ReplyMessage.USER_EXCEPTION, exception );
 575                 messageMediator.setDIIException(newException);
 576 
 577             } else {
 578                 ApplicationException appException =
 579                     new ApplicationException(
 580                         exceptionRepoId,
 581                         (org.omg.CORBA.portable.InputStream)inputObject);
 582                 exception = appException;
 583                 newException = orb.getPIHandler().invokeClientPIEndingPoint(
 584                                    ReplyMessage.USER_EXCEPTION, appException );
 585             }
 586 
 587             if (newException != exception) {
 588                 continueOrThrowSystemOrRemarshal(messageMediator,newException);
 589             }
 590 
 591             if (newException instanceof ApplicationException) {
 592                 throw (ApplicationException)newException;
 593             }
 594             // For DII:
 595             // This return will be ignored - already unmarshaled above.
 596             return inputObject;
 597 
 598         } else if (messageMediator.isLocationForwardReply()) {
 599 
 600             if (orb.subcontractDebugFlag) {
 601                 dprint(".processResponse: " + opAndId(messageMediator)
 602                        + ": received location forward");
 603             }
 604 
 605             // NOTE: Expects iterator to update target IOR
 606             getContactInfoListIterator(orb).reportRedirect(
 607                 (CorbaContactInfo)messageMediator.getContactInfo(),
 608                 messageMediator.getForwardedIOR());
 609 
 610             // Invoke Portable Interceptors with receive_other:
 611             Exception newException = orb.getPIHandler().invokeClientPIEndingPoint(
 612                 ReplyMessage.LOCATION_FORWARD, null );
 613 
 614             if( !(newException instanceof RemarshalException) ) {
 615                 exception = newException;
 616             }
 617 
 618             // If PI did not change exception, throw Remarshal, else
 619             // throw the exception PI wants thrown.
 620             // KMC: GenericPOAClientSC did not check exception != null
 621             if( exception != null ) {
 622                 continueOrThrowSystemOrRemarshal(messageMediator, exception);
 623             }
 624             continueOrThrowSystemOrRemarshal(messageMediator,
 625                                              new RemarshalException());
 626             throw wrapper.statementNotReachable5() ;
 627 
 628         } else if (messageMediator.isDifferentAddrDispositionRequestedReply()){
 629 
 630             if (orb.subcontractDebugFlag) {
 631                 dprint(".processResponse: " + opAndId(messageMediator)
 632                        + ": received different addressing dispostion request");
 633             }
 634 
 635             // Set the desired target addressing disposition.
 636             getContactInfoListIterator(orb).reportAddrDispositionRetry(
 637                 (CorbaContactInfo)messageMediator.getContactInfo(),
 638                 messageMediator.getAddrDispositionReply());
 639 
 640             // Invoke Portable Interceptors with receive_other:
 641             Exception newException = orb.getPIHandler().invokeClientPIEndingPoint(
 642                 ReplyMessage.NEEDS_ADDRESSING_MODE, null);
 643 
 644             // For consistency with corresponding code in GenericPOAClientSC:
 645             if( !(newException instanceof RemarshalException) ) {
 646                 exception = newException;
 647             }
 648 
 649             // If PI did not change exception, throw Remarshal, else
 650             // throw the exception PI wants thrown.
 651             // KMC: GenericPOAClientSC did not include exception != null check
 652             if( exception != null ) {
 653                 continueOrThrowSystemOrRemarshal(messageMediator, exception);
 654             }
 655             continueOrThrowSystemOrRemarshal(messageMediator,
 656                                              new RemarshalException());
 657             throw wrapper.statementNotReachable6() ;
 658         } else /* normal response */ {
 659 
 660             if (orb.subcontractDebugFlag) {
 661                 dprint(".processResponse: " + opAndId(messageMediator)
 662                        + ": received normal response");
 663             }
 664 
 665             getContactInfoListIterator(orb)
 666                 .reportSuccess(messageMediator.getContactInfo());
 667 
 668             messageMediator.handleDIIReply((InputStream)inputObject);
 669 
 670             // Invoke Portable Interceptors with receive_reply:
 671             exception = orb.getPIHandler().invokeClientPIEndingPoint(
 672                 ReplyMessage.NO_EXCEPTION, null );
 673 
 674             // Remember: not thrown if exception is null.
 675             continueOrThrowSystemOrRemarshal(messageMediator, exception);
 676 
 677             return inputObject;
 678         }
 679     }
 680 
 681     // Filters the given exception into a SystemException or a
 682     // RemarshalException and throws it.  Assumes the given exception is
 683     // of one of these two types.  This is a utility method for
 684     // the above invoke code which must do this numerous times.
 685     // If the exception is null, no exception is thrown.
 686     //
 687     // Note that this code is duplicated in GenericPOAClientSC.java
 688     protected void continueOrThrowSystemOrRemarshal(
 689         CorbaMessageMediator messageMediator, Exception exception)
 690         throws
 691             SystemException, RemarshalException
 692     {
 693 
 694         ORB orb = (ORB) messageMediator.getBroker();
 695 
 696         if( exception == null ) {
 697 
 698             // do nothing.
 699 
 700         } else if( exception instanceof RemarshalException ) {
 701 
 702             // REVISIT - unify with PI handling
 703             orb.getInvocationInfo().setIsRetryInvocation(true);
 704 
 705             // NOTE - We must unregister the waiter NOW for this request
 706             // since the retry will result in a new request id.  Therefore
 707             // the old request id would be lost and we would have a memory
 708             // leak in the responseWaitingRoom.
 709             unregisterWaiter(orb);
 710 
 711             if (orb.subcontractDebugFlag) {
 712                 dprint(".continueOrThrowSystemOrRemarshal: "
 713                        + opAndId(messageMediator)
 714                        + ": throwing Remarshal");
 715             }
 716 
 717             throw (RemarshalException)exception;
 718 
 719         } else {
 720 
 721             if (orb.subcontractDebugFlag) {
 722                 dprint(".continueOrThrowSystemOrRemarshal: "
 723                        + opAndId(messageMediator)
 724                        + ": throwing sex:"
 725                        + exception);
 726             }
 727 
 728             throw (SystemException)exception;
 729         }
 730     }
 731 
 732     protected CorbaContactInfoListIterator  getContactInfoListIterator(ORB orb)
 733     {
 734         return (CorbaContactInfoListIterator)
 735             ((CorbaInvocationInfo)orb.getInvocationInfo())
 736                 .getContactInfoListIterator();
 737     }
 738 
 739     protected void registerWaiter(CorbaMessageMediator messageMediator)
 740     {
 741         if (messageMediator.getConnection() != null) {
 742             messageMediator.getConnection().registerWaiter(messageMediator);
 743         }
 744     }
 745 
 746     protected void unregisterWaiter(ORB orb)
 747     {
 748         MessageMediator messageMediator =
 749             orb.getInvocationInfo().getMessageMediator();
 750         if (messageMediator!=null && messageMediator.getConnection() != null) {
 751             // REVISIT:
 752             // The messageMediator may be null if COMM_FAILURE before
 753             // it is created.
 754             messageMediator.getConnection().unregisterWaiter(messageMediator);
 755         }
 756     }
 757 
 758     protected void addServiceContexts(CorbaMessageMediator messageMediator)
 759     {
 760         ORB orb = (ORB)messageMediator.getBroker();
 761         CorbaConnection c = (CorbaConnection) messageMediator.getConnection();
 762         GIOPVersion giopVersion = messageMediator.getGIOPVersion();
 763 
 764         ServiceContexts contexts = messageMediator.getRequestServiceContexts();
 765 
 766         addCodeSetServiceContext(c, contexts, giopVersion);
 767 
 768         // Add the RMI-IIOP max stream format version
 769         // service context to every request.  Once we have GIOP 1.3,
 770         // we could skip it since we now support version 2, but
 771         // probably safer to always send it.
 772         contexts.put(MaxStreamFormatVersionServiceContext.singleton);
 773 
 774         // ORBVersion servicecontext needs to be sent
 775         ORBVersionServiceContext ovsc = new ORBVersionServiceContext(
 776                         ORBVersionFactory.getORBVersion() ) ;
 777         contexts.put( ovsc ) ;
 778 
 779         // NOTE : We only want to send the runtime context the first time
 780         if ((c != null) && !c.isPostInitialContexts()) {
 781             // Do not do c.setPostInitialContexts() here.
 782             // If a client interceptor send_request does a ForwardRequest
 783             // which ends up using the same connection then the service
 784             // context would not be sent.
 785             SendingContextServiceContext scsc =
 786                 new SendingContextServiceContext( orb.getFVDCodeBaseIOR() ) ; //d11638
 787             contexts.put( scsc ) ;
 788         }
 789     }
 790 
 791     protected void consumeServiceContexts(ORB orb,
 792                                         CorbaMessageMediator messageMediator)
 793     {
 794         ServiceContexts ctxts = messageMediator.getReplyServiceContexts();
 795         ServiceContext sc ;
 796         ORBUtilSystemException wrapper = ORBUtilSystemException.get( orb,
 797                 CORBALogDomains.RPC_PROTOCOL ) ;
 798 
 799         if (ctxts == null) {
 800             return; // no service context available, return gracefully.
 801         }
 802 
 803         sc = ctxts.get( SendingContextServiceContext.SERVICE_CONTEXT_ID ) ;
 804 
 805         if (sc != null) {
 806             SendingContextServiceContext scsc =
 807                 (SendingContextServiceContext)sc ;
 808             IOR ior = scsc.getIOR() ;
 809 
 810             try {
 811                 // set the codebase returned by the server
 812                 if (messageMediator.getConnection() != null) {
 813                     ((CorbaConnection)messageMediator.getConnection()).setCodeBaseIOR(ior);
 814                 }
 815             } catch (ThreadDeath td) {
 816                 throw td ;
 817             } catch (Throwable t) {
 818                 throw wrapper.badStringifiedIor( t ) ;
 819             }
 820         }
 821 
 822         // see if the version subcontract is present, if yes, then set
 823         // the ORBversion
 824         sc = ctxts.get( ORBVersionServiceContext.SERVICE_CONTEXT_ID ) ;
 825 
 826         if (sc != null) {
 827             ORBVersionServiceContext ovsc =
 828                (ORBVersionServiceContext) sc;
 829 
 830             ORBVersion version = ovsc.getVersion();
 831             orb.setORBVersion( version ) ;
 832         }
 833 
 834         getExceptionDetailMessage(messageMediator, wrapper);
 835     }
 836 
 837     protected void getExceptionDetailMessage(
 838         CorbaMessageMediator  messageMediator,
 839         ORBUtilSystemException wrapper)
 840     {
 841         ServiceContext sc = messageMediator.getReplyServiceContexts()
 842             .get(ExceptionDetailMessage.value);
 843         if (sc == null)
 844             return ;
 845 
 846         if (! (sc instanceof UnknownServiceContext)) {
 847             throw wrapper.badExceptionDetailMessageServiceContextType();
 848         }
 849         byte[] data = ((UnknownServiceContext)sc).getData();
 850         EncapsInputStream in =
 851                 EncapsInputStreamFactory.newEncapsInputStream((ORB)messageMediator.getBroker(),
 852                                       data, data.length);
 853         in.consumeEndian();
 854 
 855         String msg =
 856               "----------BEGIN server-side stack trace----------\n"
 857             + in.read_wstring() + "\n"
 858             + "----------END server-side stack trace----------";
 859 
 860         messageMediator.setReplyExceptionDetailMessage(msg);
 861     }
 862 
 863     public void endRequest(Broker broker, Object self, InputObject inputObject)
 864     {
 865         ORB orb = (ORB)broker ;
 866 
 867         try {
 868             if (orb.subcontractDebugFlag) {
 869                 dprint(".endRequest->");
 870             }
 871 
 872             // Note: the inputObject may be null if an error occurs
 873             //       in request or before _invoke returns.
 874             // Note: self may be null also (e.g., compiler generates null in stub).
 875 
 876             MessageMediator messageMediator =
 877                 orb.getInvocationInfo().getMessageMediator();
 878             if (messageMediator != null)
 879             {
 880                 if (messageMediator.getConnection() != null)
 881                 {
 882                     ((CorbaMessageMediator)messageMediator)
 883                               .sendCancelRequestIfFinalFragmentNotSent();
 884                 }
 885 
 886                 // Release any outstanding NIO ByteBuffers to the ByteBufferPool
 887 
 888                 InputObject inputObj = messageMediator.getInputObject();
 889                 if (inputObj != null) {
 890                     inputObj.close();
 891                 }
 892 
 893                 OutputObject outputObj = messageMediator.getOutputObject();
 894                 if (outputObj != null) {
 895                     outputObj.close();
 896                 }
 897 
 898             }
 899 
 900             // XREVISIT NOTE - Assumes unregistering the waiter for
 901             // location forwards has already happened somewhere else.
 902             // The code below is only going to unregister the final successful
 903             // request.
 904 
 905             // NOTE: In the case of a recursive stack of endRequests in a
 906             // finally block (because of Remarshal) only the first call to
 907             // unregisterWaiter will remove the waiter.  The rest will be
 908             // noops.
 909             unregisterWaiter(orb);
 910 
 911             // Invoke Portable Interceptors cleanup.  This is done to handle
 912             // exceptions during stream marshaling.  More generally, exceptions
 913             // that occur in the ORB after send_request (which includes
 914             // after returning from _request) before _invoke:
 915             orb.getPIHandler().cleanupClientPIRequest();
 916 
 917             // REVISIT: Early replies?
 918         } catch (IOException ex) {
 919             // See CDRInput/OutputObject.close() for more info.
 920             // This won't result in a Corba error if an IOException happens.
 921             if (orb.subcontractDebugFlag)
 922             {
 923                 dprint(".endRequest: ignoring IOException - " + ex.toString());
 924             }
 925         } finally {
 926             if (orb.subcontractDebugFlag) {
 927                 dprint(".endRequest<-");
 928             }
 929         }
 930     }
 931 
 932 
 933     protected void performCodeSetNegotiation(CorbaMessageMediator messageMediator)
 934     {
 935         CorbaConnection conn =
 936             (CorbaConnection) messageMediator.getConnection();
 937         IOR ior =
 938             ((CorbaContactInfo)messageMediator.getContactInfo())
 939             .getEffectiveTargetIOR();
 940         GIOPVersion giopVersion = messageMediator.getGIOPVersion();
 941 
 942         // XXX This seems to be a broken double checked locking idiom: FIX IT!
 943 
 944         // conn.getCodeSetContext() is null when no other requests have
 945         // been made on this connection to trigger code set negotation.
 946         if (conn != null &&
 947             conn.getCodeSetContext() == null &&
 948             !giopVersion.equals(GIOPVersion.V1_0)) {
 949 
 950             synchronized(conn) {
 951                 // Double checking.  Don't let any other
 952                 // threads use this connection until the
 953                 // code sets are straight.
 954                 if (conn.getCodeSetContext() != null)
 955                     return;
 956 
 957                 // This only looks at the first code set component.  If
 958                 // there can be multiple locations with multiple code sets,
 959                 // this requires more work.
 960                 IIOPProfileTemplate temp =
 961                     (IIOPProfileTemplate)ior.getProfile().
 962                     getTaggedProfileTemplate();
 963                 Iterator iter = temp.iteratorById(TAG_CODE_SETS.value);
 964                 if (!iter.hasNext()) {
 965                     // Didn't have a code set component.  The default will
 966                     // be to use ISO8859-1 for char data and throw an
 967                     // exception if wchar data is used.
 968                     return;
 969                 }
 970 
 971                 // Get the native and conversion code sets the
 972                 // server specified in its IOR
 973                 CodeSetComponentInfo serverCodeSets
 974                     = ((CodeSetsComponent)iter.next()).getCodeSetComponentInfo();
 975 
 976                 // Perform the negotiation between this ORB's code sets and
 977                 // the ones from the IOR
 978                 CodeSetComponentInfo.CodeSetContext result
 979                     = CodeSetConversion.impl().negotiate(
 980                           conn.getBroker().getORBData().getCodeSetComponentInfo(),
 981                           serverCodeSets);
 982 
 983                 conn.setCodeSetContext(result);
 984             }
 985         }
 986     }
 987 
 988     protected void addCodeSetServiceContext(CorbaConnection conn,
 989                                           ServiceContexts ctxs,
 990                                           GIOPVersion giopVersion) {
 991 
 992         // REVISIT.  OMG issue 3318 concerning sending the code set
 993         // service context more than once was deemed too much for the
 994         // RTF.  Here's our strategy for the moment:
 995         //
 996         // Send it on every request (necessary in cases of fragmentation
 997         // with multithreaded clients or when the first thing on a
 998         // connection is a LocateRequest).  Provide an ORB property
 999         // to disable multiple sends.
1000         //
1001         // Note that the connection is null in the local case and no
1002         // service context is included.  We use the ORB provided
1003         // encapsulation streams.
1004         //
1005         // Also, there will be no negotiation or service context
1006         // in GIOP 1.0.  ISO8859-1 is used for char/string, and
1007         // wchar/wstring are illegal.
1008         //
1009         if (giopVersion.equals(GIOPVersion.V1_0) || conn == null)
1010             return;
1011 
1012         CodeSetComponentInfo.CodeSetContext codeSetCtx = null;
1013 
1014         if (conn.getBroker().getORBData().alwaysSendCodeSetServiceContext() ||
1015             !conn.isPostInitialContexts()) {
1016 
1017             // Get the negotiated code sets (if any) out of the connection
1018             codeSetCtx = conn.getCodeSetContext();
1019         }
1020 
1021         // Either we shouldn't send the code set service context, or
1022         // for some reason, the connection doesn't have its code sets.
1023         // Perhaps the server didn't include them in the IOR.  Uses
1024         // ISO8859-1 for char and makes wchar/wstring illegal.
1025         if (codeSetCtx == null)
1026             return;
1027 
1028         CodeSetServiceContext cssc = new CodeSetServiceContext(codeSetCtx);
1029         ctxs.put(cssc);
1030     }
1031 
1032     protected String peekUserExceptionId(InputObject inputObject)
1033     {
1034         CDRInputObject cdrInputObject = (CDRInputObject) inputObject;
1035         // REVISIT - need interface for mark/reset
1036         cdrInputObject.mark(Integer.MAX_VALUE);
1037         String result = cdrInputObject.read_string();
1038         cdrInputObject.reset();
1039         return result;
1040     }
1041 
1042     protected void dprint(String msg)
1043     {
1044         ORBUtility.dprint("CorbaClientRequestDispatcherImpl", msg);
1045     }
1046 
1047     protected String opAndId(CorbaMessageMediator mediator)
1048     {
1049         return ORBUtility.operationNameAndRequestId(mediator);
1050     }
1051 }
1052 
1053 // End of file.