CorbaClientRequestDispatcherImpl.java revision 608:7e06bf1dcb09
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
33package com.sun.corba.se.impl.protocol;
34
35import java.io.IOException;
36import java.util.Iterator;
37import java.rmi.RemoteException;
38
39import javax.rmi.CORBA.Util;
40import javax.rmi.CORBA.Tie;
41
42import org.omg.CORBA.COMM_FAILURE;
43import org.omg.CORBA.INTERNAL;
44import org.omg.CORBA.SystemException;
45import org.omg.CORBA.Request;
46import org.omg.CORBA.NamedValue;
47import org.omg.CORBA.NVList;
48import org.omg.CORBA.Context;
49import org.omg.CORBA.ContextList;
50import org.omg.CORBA.ExceptionList;
51import org.omg.CORBA.TypeCode;
52import org.omg.CORBA.portable.RemarshalException;
53import org.omg.CORBA_2_3.portable.InputStream;
54import org.omg.CORBA_2_3.portable.OutputStream;
55import org.omg.CORBA.portable.Delegate;
56import org.omg.CORBA.portable.ServantObject;
57import org.omg.CORBA.portable.ApplicationException;
58import org.omg.CORBA.portable.UnknownException;
59import org.omg.IOP.ExceptionDetailMessage;
60import org.omg.IOP.TAG_CODE_SETS;
61
62import com.sun.org.omg.SendingContext.CodeBase;
63
64import com.sun.corba.se.pept.broker.Broker;
65import com.sun.corba.se.pept.encoding.InputObject;
66import com.sun.corba.se.pept.encoding.OutputObject;
67import com.sun.corba.se.pept.protocol.ClientRequestDispatcher;
68import com.sun.corba.se.pept.protocol.MessageMediator;
69import com.sun.corba.se.pept.transport.Connection;
70import com.sun.corba.se.pept.transport.OutboundConnectionCache;
71import com.sun.corba.se.pept.transport.ContactInfo;
72
73import com.sun.corba.se.spi.ior.IOR;
74import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
75import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate;
76import com.sun.corba.se.spi.ior.iiop.CodeSetsComponent;
77import com.sun.corba.se.spi.oa.OAInvocationInfo;
78import com.sun.corba.se.spi.oa.ObjectAdapterFactory;
79import com.sun.corba.se.spi.orb.ORB;
80import com.sun.corba.se.spi.orb.ORBVersion;
81import com.sun.corba.se.spi.orb.ORBVersionFactory;
82import com.sun.corba.se.spi.protocol.CorbaMessageMediator;
83import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry;
84import com.sun.corba.se.spi.transport.CorbaContactInfo ;
85import com.sun.corba.se.spi.transport.CorbaContactInfoList ;
86import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator ;
87import com.sun.corba.se.spi.transport.CorbaConnection;
88import com.sun.corba.se.spi.logging.CORBALogDomains;
89
90import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext;
91import com.sun.corba.se.spi.servicecontext.ServiceContext;
92import com.sun.corba.se.spi.servicecontext.ServiceContexts;
93import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext;
94import com.sun.corba.se.spi.servicecontext.CodeSetServiceContext;
95import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext;
96import com.sun.corba.se.spi.servicecontext.ORBVersionServiceContext;
97import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext;
98import com.sun.corba.se.spi.servicecontext.UnknownServiceContext;
99
100import com.sun.corba.se.impl.encoding.CDRInputObject;
101import com.sun.corba.se.impl.encoding.CodeSetComponentInfo;
102import com.sun.corba.se.impl.encoding.CodeSetConversion;
103import com.sun.corba.se.impl.encoding.EncapsInputStream;
104import com.sun.corba.se.impl.encoding.MarshalOutputStream;
105import com.sun.corba.se.impl.encoding.MarshalInputStream;
106import com.sun.corba.se.impl.logging.ORBUtilSystemException;
107import com.sun.corba.se.impl.orbutil.ORBUtility;
108import com.sun.corba.se.impl.orbutil.ORBConstants;
109import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage;
110import com.sun.corba.se.impl.protocol.giopmsgheaders.KeyAddr;
111import com.sun.corba.se.impl.protocol.giopmsgheaders.ProfileAddr;
112import com.sun.corba.se.impl.protocol.giopmsgheaders.ReferenceAddr;
113import com.sun.corba.se.impl.transport.CorbaContactInfoListIteratorImpl;
114import com.sun.corba.se.impl.util.JDKBridge;
115
116import java.util.concurrent.ConcurrentMap;
117import java.util.concurrent.ConcurrentHashMap;
118import 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 */
125public 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.
1054