blob: 5c669dda9f9c928ed7b9b14a3874f390b00cda70 [file] [log] [blame]
/*
* 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.