| /* |
| * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * Licensed Materials - Property of IBM |
| * RMI-IIOP v1.0 |
| * Copyright IBM Corp. 1998 1999 All Rights Reserved |
| * |
| */ |
| |
| package com.sun.corba.se.impl.protocol; |
| |
| import java.io.IOException; |
| import java.util.Iterator; |
| import java.rmi.RemoteException; |
| |
| import javax.rmi.CORBA.Util; |
| import javax.rmi.CORBA.Tie; |
| |
| import org.omg.CORBA.COMM_FAILURE; |
| import org.omg.CORBA.INTERNAL; |
| import org.omg.CORBA.SystemException; |
| import org.omg.CORBA.Request; |
| import org.omg.CORBA.NamedValue; |
| import org.omg.CORBA.NVList; |
| import org.omg.CORBA.Context; |
| import org.omg.CORBA.ContextList; |
| import org.omg.CORBA.ExceptionList; |
| import org.omg.CORBA.TypeCode; |
| import org.omg.CORBA.portable.RemarshalException; |
| import org.omg.CORBA_2_3.portable.InputStream; |
| import org.omg.CORBA_2_3.portable.OutputStream; |
| import org.omg.CORBA.portable.Delegate; |
| import org.omg.CORBA.portable.ServantObject; |
| import org.omg.CORBA.portable.ApplicationException; |
| import org.omg.CORBA.portable.UnknownException; |
| import org.omg.IOP.ExceptionDetailMessage; |
| import org.omg.IOP.TAG_CODE_SETS; |
| |
| import com.sun.org.omg.SendingContext.CodeBase; |
| |
| import com.sun.corba.se.pept.broker.Broker; |
| import com.sun.corba.se.pept.encoding.InputObject; |
| import com.sun.corba.se.pept.encoding.OutputObject; |
| import com.sun.corba.se.pept.protocol.ClientRequestDispatcher; |
| import com.sun.corba.se.pept.protocol.MessageMediator; |
| import com.sun.corba.se.pept.transport.Connection; |
| import com.sun.corba.se.pept.transport.OutboundConnectionCache; |
| import com.sun.corba.se.pept.transport.ContactInfo; |
| |
| import com.sun.corba.se.spi.ior.IOR; |
| import com.sun.corba.se.spi.ior.iiop.GIOPVersion; |
| import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate; |
| import com.sun.corba.se.spi.ior.iiop.CodeSetsComponent; |
| import com.sun.corba.se.spi.oa.OAInvocationInfo; |
| import com.sun.corba.se.spi.oa.ObjectAdapterFactory; |
| import com.sun.corba.se.spi.orb.ORB; |
| import com.sun.corba.se.spi.orb.ORBVersion; |
| import com.sun.corba.se.spi.orb.ORBVersionFactory; |
| import com.sun.corba.se.spi.protocol.CorbaMessageMediator; |
| import com.sun.corba.se.spi.protocol.RequestDispatcherRegistry; |
| import com.sun.corba.se.spi.transport.CorbaContactInfo ; |
| import com.sun.corba.se.spi.transport.CorbaContactInfoList ; |
| import com.sun.corba.se.spi.transport.CorbaContactInfoListIterator ; |
| import com.sun.corba.se.spi.transport.CorbaConnection; |
| import com.sun.corba.se.spi.logging.CORBALogDomains; |
| |
| import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext; |
| import com.sun.corba.se.spi.servicecontext.ServiceContext; |
| import com.sun.corba.se.spi.servicecontext.ServiceContexts; |
| import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext; |
| import com.sun.corba.se.spi.servicecontext.CodeSetServiceContext; |
| import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext; |
| import com.sun.corba.se.spi.servicecontext.ORBVersionServiceContext; |
| import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext; |
| import com.sun.corba.se.spi.servicecontext.UnknownServiceContext; |
| |
| import com.sun.corba.se.impl.encoding.CDRInputObject; |
| import com.sun.corba.se.impl.encoding.CodeSetComponentInfo; |
| import com.sun.corba.se.impl.encoding.CodeSetConversion; |
| import com.sun.corba.se.impl.encoding.EncapsInputStream; |
| import com.sun.corba.se.impl.encoding.MarshalOutputStream; |
| import com.sun.corba.se.impl.encoding.MarshalInputStream; |
| import com.sun.corba.se.impl.logging.ORBUtilSystemException; |
| import com.sun.corba.se.impl.orbutil.ORBUtility; |
| import com.sun.corba.se.impl.orbutil.ORBConstants; |
| import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage; |
| import com.sun.corba.se.impl.protocol.giopmsgheaders.KeyAddr; |
| import com.sun.corba.se.impl.protocol.giopmsgheaders.ProfileAddr; |
| import com.sun.corba.se.impl.protocol.giopmsgheaders.ReferenceAddr; |
| import com.sun.corba.se.impl.transport.CorbaContactInfoListIteratorImpl; |
| import com.sun.corba.se.impl.util.JDKBridge; |
| |
| import java.util.concurrent.ConcurrentMap; |
| import java.util.concurrent.ConcurrentHashMap; |
| import sun.corba.EncapsInputStreamFactory; |
| |
| /** |
| * ClientDelegate is the RMI client-side subcontract or representation |
| * It implements RMI delegate as well as our internal ClientRequestDispatcher |
| * interface. |
| */ |
| public class CorbaClientRequestDispatcherImpl |
| implements |
| ClientRequestDispatcher |
| { |
| private ConcurrentMap<ContactInfo, Object> locks = |
| new ConcurrentHashMap<ContactInfo, Object>(); |
| |
| public OutputObject beginRequest(Object self, String opName, |
| boolean isOneWay, ContactInfo contactInfo) |
| { |
| ORB orb = null; |
| try { |
| CorbaContactInfo corbaContactInfo = (CorbaContactInfo) contactInfo; |
| orb = (ORB)contactInfo.getBroker(); |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest->: op/" + opName); |
| } |
| |
| // |
| // Portable Interceptor initialization. |
| // |
| |
| orb.getPIHandler().initiateClientPIRequest( false ); |
| |
| // |
| // Connection. |
| // |
| |
| CorbaConnection connection = null; |
| |
| // This locking is done so that multiple connections are not created |
| // for the same endpoint |
| // 7046238 - Synchronization on a single monitor for contactInfo parameters |
| // with identical hashCode(), so we lock on same monitor for equal parameters |
| // (which can refer to equal (in terms of equals()) but not the same objects) |
| |
| Object lock = locks.get(contactInfo); |
| |
| if (lock == null) { |
| Object newLock = new Object(); |
| lock = locks.putIfAbsent(contactInfo, newLock); |
| if (lock == null) { |
| lock = newLock; |
| } |
| } |
| |
| synchronized (lock) { |
| if (contactInfo.isConnectionBased()) { |
| if (contactInfo.shouldCacheConnection()) { |
| connection = (CorbaConnection) |
| orb.getTransportManager() |
| .getOutboundConnectionCache(contactInfo).get(contactInfo); |
| } |
| if (connection != null) { |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: op/" + opName |
| + ": Using cached connection: " + connection); |
| } |
| } else { |
| try { |
| connection = (CorbaConnection) |
| contactInfo.createConnection(); |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: op/" + opName |
| + ": Using created connection: " + connection); |
| } |
| } catch (RuntimeException e) { |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: op/" + opName |
| + ": failed to create connection: " + e); |
| } |
| // REVISIT: this part similar to marshalingComplete below. |
| boolean retry = getContactInfoListIterator(orb) |
| .reportException(contactInfo, e); |
| // REVISIT: |
| // this part similar to Remarshal in this method below |
| if (retry) { |
| if(getContactInfoListIterator(orb).hasNext()) { |
| contactInfo = (ContactInfo) |
| getContactInfoListIterator(orb).next(); |
| unregisterWaiter(orb); |
| return beginRequest(self, opName, |
| isOneWay, contactInfo); |
| } else { |
| throw e; |
| } |
| } else { |
| throw e; |
| } |
| } |
| if (connection.shouldRegisterReadEvent()) { |
| // REVISIT: cast |
| orb.getTransportManager().getSelector(0) |
| .registerForEvent(connection.getEventHandler()); |
| connection.setState("ESTABLISHED"); |
| } |
| // Do not do connection reclaim here since the connections |
| // are marked in use by registerWaiter() call and since this |
| // call happens later do it after that. |
| if (contactInfo.shouldCacheConnection()) { |
| OutboundConnectionCache connectionCache = |
| orb.getTransportManager() |
| .getOutboundConnectionCache(contactInfo); |
| connectionCache.stampTime(connection); |
| connectionCache.put(contactInfo, connection); |
| // connectionCache.reclaim(); |
| } |
| } |
| } |
| } |
| |
| CorbaMessageMediator messageMediator = (CorbaMessageMediator) |
| contactInfo.createMessageMediator( |
| orb, contactInfo, connection, opName, isOneWay); |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: " + opAndId(messageMediator) |
| + ": created message mediator: " + messageMediator); |
| } |
| |
| // NOTE: Thread data so we can get the mediator in release reply |
| // in order to remove the waiter in CorbaConnection. |
| // We cannot depend on obtaining information in releaseReply |
| // via its InputStream argument since, on certain errors |
| // (e.g., client marshaling errors), the stream may be null. |
| // Likewise for releaseReply "self". |
| // NOTE: This must be done before initializing the message since |
| // that may start sending fragments which may end up in "early" |
| // replies or client marshaling exceptions. |
| |
| orb.getInvocationInfo().setMessageMediator(messageMediator); |
| |
| if (connection != null && connection.getCodeSetContext() == null) { |
| performCodeSetNegotiation(messageMediator); |
| } |
| |
| addServiceContexts(messageMediator); |
| |
| OutputObject outputObject = |
| contactInfo.createOutputObject(messageMediator); |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: " + opAndId(messageMediator) |
| + ": created output object: " + outputObject); |
| } |
| |
| |
| // NOTE: Not necessary for oneways, but useful for debugging. |
| // This must be done BEFORE message initialization since fragments |
| // may be sent at that time. |
| registerWaiter(messageMediator); |
| |
| // Do connection reclaim now |
| synchronized (lock) { |
| if (contactInfo.isConnectionBased()) { |
| if (contactInfo.shouldCacheConnection()) { |
| OutboundConnectionCache connectionCache = |
| orb.getTransportManager() |
| .getOutboundConnectionCache(contactInfo); |
| connectionCache.reclaim(); |
| } |
| } |
| } |
| |
| orb.getPIHandler().setClientPIInfo(messageMediator); |
| try { |
| // This MUST come before message is initialized so |
| // service contexts may be added by PI because |
| // initial fragments may be sent during message initialization. |
| orb.getPIHandler().invokeClientPIStartingPoint(); |
| } catch( RemarshalException e ) { |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: " + opAndId(messageMediator) |
| + ": Remarshal"); |
| } |
| |
| // NOTE: We get here because an interceptor raised ForwardRequest |
| // and updated the IOR/Iterator. Since we have a fresh iterator |
| // hasNext should succeed. |
| |
| // REVISIT: We should feed ALL interceptor exceptions to |
| // iterator.reportException so it can determine if it wants |
| // to retry. Right now, SystemExceptions will flow to the |
| // client code. |
| |
| // REVISIT: |
| // This assumes that interceptors update |
| // ContactInfoList outside of subcontract. |
| // Want to move that update to here. |
| if (getContactInfoListIterator(orb).hasNext()) { |
| contactInfo = (ContactInfo)getContactInfoListIterator(orb).next(); |
| if (orb.subcontractDebugFlag) { |
| dprint( "RemarshalException: hasNext true\ncontact info " + contactInfo ); |
| } |
| |
| // Fix for 6763340: Complete the first attempt before starting another. |
| orb.getPIHandler().makeCompletedClientRequest( |
| ReplyMessage.LOCATION_FORWARD, null ) ; |
| unregisterWaiter(orb); |
| orb.getPIHandler().cleanupClientPIRequest() ; |
| |
| return beginRequest(self, opName, isOneWay, contactInfo); |
| } else { |
| if (orb.subcontractDebugFlag) { |
| dprint( "RemarshalException: hasNext false" ); |
| } |
| ORBUtilSystemException wrapper = |
| ORBUtilSystemException.get(orb, |
| CORBALogDomains.RPC_PROTOCOL); |
| throw wrapper.remarshalWithNowhereToGo(); |
| } |
| } |
| |
| messageMediator.initializeMessage(); |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest: " + opAndId(messageMediator) |
| + ": initialized message"); |
| } |
| |
| return outputObject; |
| |
| } finally { |
| if (orb.subcontractDebugFlag) { |
| dprint(".beginRequest<-: op/" + opName); |
| } |
| } |
| } |
| |
| public InputObject marshalingComplete(java.lang.Object self, |
| OutputObject outputObject) |
| throws |
| ApplicationException, |
| org.omg.CORBA.portable.RemarshalException |
| { |
| ORB orb = null; |
| CorbaMessageMediator messageMediator = null; |
| try { |
| messageMediator = (CorbaMessageMediator) |
| outputObject.getMessageMediator(); |
| |
| orb = (ORB) messageMediator.getBroker(); |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".marshalingComplete->: " + opAndId(messageMediator)); |
| } |
| |
| InputObject inputObject = |
| marshalingComplete1(orb, messageMediator); |
| |
| return processResponse(orb, messageMediator, inputObject); |
| |
| } finally { |
| if (orb.subcontractDebugFlag) { |
| dprint(".marshalingComplete<-: " + opAndId(messageMediator)); |
| } |
| } |
| } |
| |
| public InputObject marshalingComplete1( |
| ORB orb, CorbaMessageMediator messageMediator) |
| throws |
| ApplicationException, |
| org.omg.CORBA.portable.RemarshalException |
| { |
| try { |
| messageMediator.finishSendingRequest(); |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".marshalingComplete: " + opAndId(messageMediator) |
| + ": finished sending request"); |
| } |
| |
| return messageMediator.waitForResponse(); |
| |
| } catch (RuntimeException e) { |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".marshalingComplete: " + opAndId(messageMediator) |
| + ": exception: " + e.toString()); |
| } |
| |
| boolean retry = |
| getContactInfoListIterator(orb) |
| .reportException(messageMediator.getContactInfo(), e); |
| |
| //Bug 6382377: must not lose exception in PI |
| |
| // Must run interceptor end point before retrying. |
| Exception newException = |
| orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.SYSTEM_EXCEPTION, e); |
| |
| if (retry) { |
| if (newException == e) { |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| new RemarshalException()); |
| } else { |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| newException); |
| } |
| } else { |
| if (newException instanceof RuntimeException){ |
| throw (RuntimeException)newException; |
| } |
| else if (newException instanceof RemarshalException) |
| { |
| throw (RemarshalException)newException; |
| } |
| |
| // NOTE: Interceptor ending point will run in releaseReply. |
| throw e; |
| } |
| return null; // for compiler |
| } |
| } |
| |
| protected InputObject processResponse(ORB orb, |
| CorbaMessageMediator messageMediator, |
| InputObject inputObject) |
| throws |
| ApplicationException, |
| org.omg.CORBA.portable.RemarshalException |
| { |
| ORBUtilSystemException wrapper = |
| ORBUtilSystemException.get( orb, |
| CORBALogDomains.RPC_PROTOCOL ) ; |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": response received"); |
| } |
| |
| // We know for sure now that we've sent a message. |
| // So OK to not send initial again. |
| if (messageMediator.getConnection() != null) { |
| ((CorbaConnection)messageMediator.getConnection()) |
| .setPostInitialContexts(); |
| } |
| |
| // NOTE: not necessary to set MessageMediator for PI. |
| // It already has it. |
| |
| // Process the response. |
| |
| Exception exception = null; |
| |
| if (messageMediator.isOneWay()) { |
| getContactInfoListIterator(orb) |
| .reportSuccess(messageMediator.getContactInfo()); |
| // Invoke Portable Interceptors with receive_other |
| exception = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.NO_EXCEPTION, exception ); |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| return null; |
| } |
| |
| consumeServiceContexts(orb, messageMediator); |
| |
| // Now that we have the service contexts processed and the |
| // correct ORBVersion set, we must finish initializing the stream. |
| // REVISIT - need interface for this operation. |
| ((CDRInputObject)inputObject).performORBVersionSpecificInit(); |
| |
| if (messageMediator.isSystemExceptionReply()) { |
| |
| SystemException se = messageMediator.getSystemExceptionReply(); |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": received system exception: " + se); |
| } |
| |
| boolean doRemarshal = |
| getContactInfoListIterator(orb) |
| .reportException(messageMediator.getContactInfo(), se); |
| |
| if (doRemarshal) { |
| |
| // Invoke Portable Interceptors with receive_exception: |
| exception = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.SYSTEM_EXCEPTION, se ); |
| |
| // If PI did not change the exception, throw a |
| // Remarshal. |
| if( se == exception ) { |
| // exception = null is to maintain symmetry with |
| // GenericPOAClientSC. |
| exception = null; |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| new RemarshalException()); |
| throw wrapper.statementNotReachable1() ; |
| } else { |
| // Otherwise, throw the exception PI wants thrown. |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| exception); |
| throw wrapper.statementNotReachable2() ; |
| } |
| } |
| |
| // No retry, so see if was unknown. |
| |
| ServiceContexts contexts = |
| messageMediator.getReplyServiceContexts(); |
| if (contexts != null) { |
| UEInfoServiceContext usc = |
| (UEInfoServiceContext) |
| contexts.get(UEInfoServiceContext.SERVICE_CONTEXT_ID); |
| |
| if (usc != null) { |
| Throwable unknown = usc.getUE() ; |
| UnknownException ue = new UnknownException(unknown); |
| |
| // Invoke Portable Interceptors with receive_exception: |
| exception = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.SYSTEM_EXCEPTION, ue ); |
| |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| throw wrapper.statementNotReachable3() ; |
| } |
| } |
| |
| // It was not a comm failure nor unknown. |
| // This is the general case. |
| |
| // Invoke Portable Interceptors with receive_exception: |
| exception = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.SYSTEM_EXCEPTION, se ); |
| |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| |
| // Note: We should never need to execute this line, but |
| // we should assert in case exception is null somehow. |
| throw wrapper.statementNotReachable4() ; |
| } else if (messageMediator.isUserExceptionReply()) { |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": received user exception"); |
| } |
| |
| getContactInfoListIterator(orb) |
| .reportSuccess(messageMediator.getContactInfo()); |
| |
| String exceptionRepoId = peekUserExceptionId(inputObject); |
| Exception newException = null; |
| |
| if (messageMediator.isDIIRequest()) { |
| exception = messageMediator.unmarshalDIIUserException( |
| exceptionRepoId, (InputStream)inputObject); |
| newException = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.USER_EXCEPTION, exception ); |
| messageMediator.setDIIException(newException); |
| |
| } else { |
| ApplicationException appException = |
| new ApplicationException( |
| exceptionRepoId, |
| (org.omg.CORBA.portable.InputStream)inputObject); |
| exception = appException; |
| newException = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.USER_EXCEPTION, appException ); |
| } |
| |
| if (newException != exception) { |
| continueOrThrowSystemOrRemarshal(messageMediator,newException); |
| } |
| |
| if (newException instanceof ApplicationException) { |
| throw (ApplicationException)newException; |
| } |
| // For DII: |
| // This return will be ignored - already unmarshaled above. |
| return inputObject; |
| |
| } else if (messageMediator.isLocationForwardReply()) { |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": received location forward"); |
| } |
| |
| // NOTE: Expects iterator to update target IOR |
| getContactInfoListIterator(orb).reportRedirect( |
| (CorbaContactInfo)messageMediator.getContactInfo(), |
| messageMediator.getForwardedIOR()); |
| |
| // Invoke Portable Interceptors with receive_other: |
| Exception newException = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.LOCATION_FORWARD, null ); |
| |
| if( !(newException instanceof RemarshalException) ) { |
| exception = newException; |
| } |
| |
| // If PI did not change exception, throw Remarshal, else |
| // throw the exception PI wants thrown. |
| // KMC: GenericPOAClientSC did not check exception != null |
| if( exception != null ) { |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| } |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| new RemarshalException()); |
| throw wrapper.statementNotReachable5() ; |
| |
| } else if (messageMediator.isDifferentAddrDispositionRequestedReply()){ |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": received different addressing dispostion request"); |
| } |
| |
| // Set the desired target addressing disposition. |
| getContactInfoListIterator(orb).reportAddrDispositionRetry( |
| (CorbaContactInfo)messageMediator.getContactInfo(), |
| messageMediator.getAddrDispositionReply()); |
| |
| // Invoke Portable Interceptors with receive_other: |
| Exception newException = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.NEEDS_ADDRESSING_MODE, null); |
| |
| // For consistency with corresponding code in GenericPOAClientSC: |
| if( !(newException instanceof RemarshalException) ) { |
| exception = newException; |
| } |
| |
| // If PI did not change exception, throw Remarshal, else |
| // throw the exception PI wants thrown. |
| // KMC: GenericPOAClientSC did not include exception != null check |
| if( exception != null ) { |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| } |
| continueOrThrowSystemOrRemarshal(messageMediator, |
| new RemarshalException()); |
| throw wrapper.statementNotReachable6() ; |
| } else /* normal response */ { |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".processResponse: " + opAndId(messageMediator) |
| + ": received normal response"); |
| } |
| |
| getContactInfoListIterator(orb) |
| .reportSuccess(messageMediator.getContactInfo()); |
| |
| messageMediator.handleDIIReply((InputStream)inputObject); |
| |
| // Invoke Portable Interceptors with receive_reply: |
| exception = orb.getPIHandler().invokeClientPIEndingPoint( |
| ReplyMessage.NO_EXCEPTION, null ); |
| |
| // Remember: not thrown if exception is null. |
| continueOrThrowSystemOrRemarshal(messageMediator, exception); |
| |
| return inputObject; |
| } |
| } |
| |
| // Filters the given exception into a SystemException or a |
| // RemarshalException and throws it. Assumes the given exception is |
| // of one of these two types. This is a utility method for |
| // the above invoke code which must do this numerous times. |
| // If the exception is null, no exception is thrown. |
| // |
| // Note that this code is duplicated in GenericPOAClientSC.java |
| protected void continueOrThrowSystemOrRemarshal( |
| CorbaMessageMediator messageMediator, Exception exception) |
| throws |
| SystemException, RemarshalException |
| { |
| |
| ORB orb = (ORB) messageMediator.getBroker(); |
| |
| if( exception == null ) { |
| |
| // do nothing. |
| |
| } else if( exception instanceof RemarshalException ) { |
| |
| // REVISIT - unify with PI handling |
| orb.getInvocationInfo().setIsRetryInvocation(true); |
| |
| // NOTE - We must unregister the waiter NOW for this request |
| // since the retry will result in a new request id. Therefore |
| // the old request id would be lost and we would have a memory |
| // leak in the responseWaitingRoom. |
| unregisterWaiter(orb); |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".continueOrThrowSystemOrRemarshal: " |
| + opAndId(messageMediator) |
| + ": throwing Remarshal"); |
| } |
| |
| throw (RemarshalException)exception; |
| |
| } else { |
| |
| if (orb.subcontractDebugFlag) { |
| dprint(".continueOrThrowSystemOrRemarshal: " |
| + opAndId(messageMediator) |
| + ": throwing sex:" |
| + exception); |
| } |
| |
| throw (SystemException)exception; |
| } |
| } |
| |
| protected CorbaContactInfoListIterator getContactInfoListIterator(ORB orb) |
| { |
| return (CorbaContactInfoListIterator) |
| ((CorbaInvocationInfo)orb.getInvocationInfo()) |
| .getContactInfoListIterator(); |
| } |
| |
| protected void registerWaiter(CorbaMessageMediator messageMediator) |
| { |
| if (messageMediator.getConnection() != null) { |
| messageMediator.getConnection().registerWaiter(messageMediator); |
| } |
| } |
| |
| protected void unregisterWaiter(ORB orb) |
| { |
| MessageMediator messageMediator = |
| orb.getInvocationInfo().getMessageMediator(); |
| if (messageMediator!=null && messageMediator.getConnection() != null) { |
| // REVISIT: |
| // The messageMediator may be null if COMM_FAILURE before |
| // it is created. |
| messageMediator.getConnection().unregisterWaiter(messageMediator); |
| } |
| } |
| |
| protected void addServiceContexts(CorbaMessageMediator messageMediator) |
| { |
| ORB orb = (ORB)messageMediator.getBroker(); |
| CorbaConnection c = (CorbaConnection) messageMediator.getConnection(); |
| GIOPVersion giopVersion = messageMediator.getGIOPVersion(); |
| |
| ServiceContexts contexts = messageMediator.getRequestServiceContexts(); |
| |
| addCodeSetServiceContext(c, contexts, giopVersion); |
| |
| // Add the RMI-IIOP max stream format version |
| // service context to every request. Once we have GIOP 1.3, |
| // we could skip it since we now support version 2, but |
| // probably safer to always send it. |
| contexts.put(MaxStreamFormatVersionServiceContext.singleton); |
| |
| // ORBVersion servicecontext needs to be sent |
| ORBVersionServiceContext ovsc = new ORBVersionServiceContext( |
| ORBVersionFactory.getORBVersion() ) ; |
| contexts.put( ovsc ) ; |
| |
| // NOTE : We only want to send the runtime context the first time |
| if ((c != null) && !c.isPostInitialContexts()) { |
| // Do not do c.setPostInitialContexts() here. |
| // If a client interceptor send_request does a ForwardRequest |
| // which ends up using the same connection then the service |
| // context would not be sent. |
| SendingContextServiceContext scsc = |
| new SendingContextServiceContext( orb.getFVDCodeBaseIOR() ) ; //d11638 |
| contexts.put( scsc ) ; |
| } |
| } |
| |
| protected void consumeServiceContexts(ORB orb, |
| CorbaMessageMediator messageMediator) |
| { |
| ServiceContexts ctxts = messageMediator.getReplyServiceContexts(); |
| ServiceContext sc ; |
| ORBUtilSystemException wrapper = ORBUtilSystemException.get( orb, |
| CORBALogDomains.RPC_PROTOCOL ) ; |
| |
| if (ctxts == null) { |
| return; // no service context available, return gracefully. |
| } |
| |
| sc = ctxts.get( SendingContextServiceContext.SERVICE_CONTEXT_ID ) ; |
| |
| if (sc != null) { |
| SendingContextServiceContext scsc = |
| (SendingContextServiceContext)sc ; |
| IOR ior = scsc.getIOR() ; |
| |
| try { |
| // set the codebase returned by the server |
| if (messageMediator.getConnection() != null) { |
| ((CorbaConnection)messageMediator.getConnection()).setCodeBaseIOR(ior); |
| } |
| } catch (ThreadDeath td) { |
| throw td ; |
| } catch (Throwable t) { |
| throw wrapper.badStringifiedIor( t ) ; |
| } |
| } |
| |
| // see if the version subcontract is present, if yes, then set |
| // the ORBversion |
| sc = ctxts.get( ORBVersionServiceContext.SERVICE_CONTEXT_ID ) ; |
| |
| if (sc != null) { |
| ORBVersionServiceContext ovsc = |
| (ORBVersionServiceContext) sc; |
| |
| ORBVersion version = ovsc.getVersion(); |
| orb.setORBVersion( version ) ; |
| } |
| |
| getExceptionDetailMessage(messageMediator, wrapper); |
| } |
| |
| protected void getExceptionDetailMessage( |
| CorbaMessageMediator messageMediator, |
| ORBUtilSystemException wrapper) |
| { |
| ServiceContext sc = messageMediator.getReplyServiceContexts() |
| .get(ExceptionDetailMessage.value); |
| if (sc == null) |
| return ; |
| |
| if (! (sc instanceof UnknownServiceContext)) { |
| throw wrapper.badExceptionDetailMessageServiceContextType(); |
| } |
| byte[] data = ((UnknownServiceContext)sc).getData(); |
| EncapsInputStream in = |
| EncapsInputStreamFactory.newEncapsInputStream((ORB)messageMediator.getBroker(), |
| data, data.length); |
| in.consumeEndian(); |
| |
| String msg = |
| "----------BEGIN server-side stack trace----------\n" |
| + in.read_wstring() + "\n" |
| + "----------END server-side stack trace----------"; |
| |
| messageMediator.setReplyExceptionDetailMessage(msg); |
| } |
| |
| public void endRequest(Broker broker, Object self, InputObject inputObject) |
| { |
| ORB orb = (ORB)broker ; |
| |
| try { |
| if (orb.subcontractDebugFlag) { |
| dprint(".endRequest->"); |
| } |
| |
| // Note: the inputObject may be null if an error occurs |
| // in request or before _invoke returns. |
| // Note: self may be null also (e.g., compiler generates null in stub). |
| |
| MessageMediator messageMediator = |
| orb.getInvocationInfo().getMessageMediator(); |
| if (messageMediator != null) |
| { |
| if (messageMediator.getConnection() != null) |
| { |
| ((CorbaMessageMediator)messageMediator) |
| .sendCancelRequestIfFinalFragmentNotSent(); |
| } |
| |
| // Release any outstanding NIO ByteBuffers to the ByteBufferPool |
| |
| InputObject inputObj = messageMediator.getInputObject(); |
| if (inputObj != null) { |
| inputObj.close(); |
| } |
| |
| OutputObject outputObj = messageMediator.getOutputObject(); |
| if (outputObj != null) { |
| outputObj.close(); |
| } |
| |
| } |
| |
| // XREVISIT NOTE - Assumes unregistering the waiter for |
| // location forwards has already happened somewhere else. |
| // The code below is only going to unregister the final successful |
| // request. |
| |
| // NOTE: In the case of a recursive stack of endRequests in a |
| // finally block (because of Remarshal) only the first call to |
| // unregisterWaiter will remove the waiter. The rest will be |
| // noops. |
| unregisterWaiter(orb); |
| |
| // Invoke Portable Interceptors cleanup. This is done to handle |
| // exceptions during stream marshaling. More generally, exceptions |
| // that occur in the ORB after send_request (which includes |
| // after returning from _request) before _invoke: |
| orb.getPIHandler().cleanupClientPIRequest(); |
| |
| // REVISIT: Early replies? |
| } catch (IOException ex) { |
| // See CDRInput/OutputObject.close() for more info. |
| // This won't result in a Corba error if an IOException happens. |
| if (orb.subcontractDebugFlag) |
| { |
| dprint(".endRequest: ignoring IOException - " + ex.toString()); |
| } |
| } finally { |
| if (orb.subcontractDebugFlag) { |
| dprint(".endRequest<-"); |
| } |
| } |
| } |
| |
| |
| protected void performCodeSetNegotiation(CorbaMessageMediator messageMediator) |
| { |
| CorbaConnection conn = |
| (CorbaConnection) messageMediator.getConnection(); |
| IOR ior = |
| ((CorbaContactInfo)messageMediator.getContactInfo()) |
| .getEffectiveTargetIOR(); |
| GIOPVersion giopVersion = messageMediator.getGIOPVersion(); |
| |
| // XXX This seems to be a broken double checked locking idiom: FIX IT! |
| |
| // conn.getCodeSetContext() is null when no other requests have |
| // been made on this connection to trigger code set negotation. |
| if (conn != null && |
| conn.getCodeSetContext() == null && |
| !giopVersion.equals(GIOPVersion.V1_0)) { |
| |
| synchronized(conn) { |
| // Double checking. Don't let any other |
| // threads use this connection until the |
| // code sets are straight. |
| if (conn.getCodeSetContext() != null) |
| return; |
| |
| // This only looks at the first code set component. If |
| // there can be multiple locations with multiple code sets, |
| // this requires more work. |
| IIOPProfileTemplate temp = |
| (IIOPProfileTemplate)ior.getProfile(). |
| getTaggedProfileTemplate(); |
| Iterator iter = temp.iteratorById(TAG_CODE_SETS.value); |
| if (!iter.hasNext()) { |
| // Didn't have a code set component. The default will |
| // be to use ISO8859-1 for char data and throw an |
| // exception if wchar data is used. |
| return; |
| } |
| |
| // Get the native and conversion code sets the |
| // server specified in its IOR |
| CodeSetComponentInfo serverCodeSets |
| = ((CodeSetsComponent)iter.next()).getCodeSetComponentInfo(); |
| |
| // Perform the negotiation between this ORB's code sets and |
| // the ones from the IOR |
| CodeSetComponentInfo.CodeSetContext result |
| = CodeSetConversion.impl().negotiate( |
| conn.getBroker().getORBData().getCodeSetComponentInfo(), |
| serverCodeSets); |
| |
| conn.setCodeSetContext(result); |
| } |
| } |
| } |
| |
| protected void addCodeSetServiceContext(CorbaConnection conn, |
| ServiceContexts ctxs, |
| GIOPVersion giopVersion) { |
| |
| // REVISIT. OMG issue 3318 concerning sending the code set |
| // service context more than once was deemed too much for the |
| // RTF. Here's our strategy for the moment: |
| // |
| // Send it on every request (necessary in cases of fragmentation |
| // with multithreaded clients or when the first thing on a |
| // connection is a LocateRequest). Provide an ORB property |
| // to disable multiple sends. |
| // |
| // Note that the connection is null in the local case and no |
| // service context is included. We use the ORB provided |
| // encapsulation streams. |
| // |
| // Also, there will be no negotiation or service context |
| // in GIOP 1.0. ISO8859-1 is used for char/string, and |
| // wchar/wstring are illegal. |
| // |
| if (giopVersion.equals(GIOPVersion.V1_0) || conn == null) |
| return; |
| |
| CodeSetComponentInfo.CodeSetContext codeSetCtx = null; |
| |
| if (conn.getBroker().getORBData().alwaysSendCodeSetServiceContext() || |
| !conn.isPostInitialContexts()) { |
| |
| // Get the negotiated code sets (if any) out of the connection |
| codeSetCtx = conn.getCodeSetContext(); |
| } |
| |
| // Either we shouldn't send the code set service context, or |
| // for some reason, the connection doesn't have its code sets. |
| // Perhaps the server didn't include them in the IOR. Uses |
| // ISO8859-1 for char and makes wchar/wstring illegal. |
| if (codeSetCtx == null) |
| return; |
| |
| CodeSetServiceContext cssc = new CodeSetServiceContext(codeSetCtx); |
| ctxs.put(cssc); |
| } |
| |
| protected String peekUserExceptionId(InputObject inputObject) |
| { |
| CDRInputObject cdrInputObject = (CDRInputObject) inputObject; |
| // REVISIT - need interface for mark/reset |
| cdrInputObject.mark(Integer.MAX_VALUE); |
| String result = cdrInputObject.read_string(); |
| cdrInputObject.reset(); |
| return result; |
| } |
| |
| protected void dprint(String msg) |
| { |
| ORBUtility.dprint("CorbaClientRequestDispatcherImpl", msg); |
| } |
| |
| protected String opAndId(CorbaMessageMediator mediator) |
| { |
| return ORBUtility.operationNameAndRequestId(mediator); |
| } |
| } |
| |
| // End of file. |