/* * 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. */ package com.sun.corba.se.impl.protocol; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.util.EmptyStackException; import java.util.Iterator; import org.omg.CORBA.Any; import org.omg.CORBA.CompletionStatus; import org.omg.CORBA.ExceptionList; import org.omg.CORBA.INTERNAL; import org.omg.CORBA.Principal; import org.omg.CORBA.SystemException; import org.omg.CORBA.TypeCode; import org.omg.CORBA.UnknownUserException; import org.omg.CORBA.UNKNOWN; import org.omg.CORBA.portable.ResponseHandler; import org.omg.CORBA.portable.UnknownException; import org.omg.CORBA_2_3.portable.InputStream; import org.omg.CORBA_2_3.portable.OutputStream; import org.omg.IOP.ExceptionDetailMessage; import org.omg.IOP.TAG_RMI_CUSTOM_MAX_STREAM_FORMAT; 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.MessageMediator; import com.sun.corba.se.pept.protocol.ProtocolHandler; import com.sun.corba.se.pept.transport.ByteBufferPool; import com.sun.corba.se.pept.transport.Connection; import com.sun.corba.se.pept.transport.ContactInfo; import com.sun.corba.se.pept.transport.EventHandler; import com.sun.corba.se.spi.ior.IOR; import com.sun.corba.se.spi.ior.ObjectKey; import com.sun.corba.se.spi.ior.ObjectKeyTemplate; 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.IIOPProfile; import com.sun.corba.se.spi.ior.iiop.MaxStreamFormatVersionComponent; import com.sun.corba.se.spi.oa.OAInvocationInfo; import com.sun.corba.se.spi.oa.ObjectAdapter; import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.spi.orb.ORBVersionFactory; import com.sun.corba.se.spi.protocol.CorbaMessageMediator; import com.sun.corba.se.spi.protocol.CorbaProtocolHandler; import com.sun.corba.se.spi.protocol.CorbaServerRequestDispatcher; import com.sun.corba.se.spi.protocol.ForwardException; import com.sun.corba.se.spi.transport.CorbaConnection; import com.sun.corba.se.spi.transport.CorbaContactInfo; import com.sun.corba.se.spi.transport.CorbaResponseWaitingRoom; import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.spi.servicecontext.ORBVersionServiceContext; import com.sun.corba.se.spi.servicecontext.ServiceContexts; import com.sun.corba.se.spi.servicecontext.UEInfoServiceContext; import com.sun.corba.se.spi.servicecontext.MaxStreamFormatVersionServiceContext; import com.sun.corba.se.spi.servicecontext.SendingContextServiceContext; import com.sun.corba.se.spi.servicecontext.UnknownServiceContext; import com.sun.corba.se.impl.corba.RequestImpl; import com.sun.corba.se.impl.encoding.BufferManagerFactory; import com.sun.corba.se.impl.encoding.BufferManagerReadStream; import com.sun.corba.se.impl.encoding.CDRInputObject; import com.sun.corba.se.impl.encoding.CDROutputObject; import com.sun.corba.se.impl.encoding.EncapsOutputStream; import com.sun.corba.se.impl.logging.ORBUtilSystemException; import com.sun.corba.se.impl.logging.InterceptorsSystemException; import com.sun.corba.se.impl.orbutil.ORBConstants; import com.sun.corba.se.impl.orbutil.ORBUtility; import com.sun.corba.se.impl.ior.iiop.JavaSerializationComponent; import com.sun.corba.se.impl.protocol.AddressingDispositionException; import com.sun.corba.se.impl.protocol.RequestCanceledException; import com.sun.corba.se.impl.protocol.giopmsgheaders.AddressingDispositionHelper; import com.sun.corba.se.impl.protocol.giopmsgheaders.CancelRequestMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.FragmentMessage_1_1; import com.sun.corba.se.impl.protocol.giopmsgheaders.FragmentMessage_1_2; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateRequestMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateRequestMessage_1_0; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateRequestMessage_1_1; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateRequestMessage_1_2; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateReplyOrReplyMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateReplyMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateReplyMessage_1_0; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateReplyMessage_1_1; import com.sun.corba.se.impl.protocol.giopmsgheaders.LocateReplyMessage_1_2; import com.sun.corba.se.impl.protocol.giopmsgheaders.Message; import com.sun.corba.se.impl.protocol.giopmsgheaders.MessageBase; import com.sun.corba.se.impl.protocol.giopmsgheaders.MessageHandler; import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage_1_0; import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage_1_1; import com.sun.corba.se.impl.protocol.giopmsgheaders.ReplyMessage_1_2; import com.sun.corba.se.impl.protocol.giopmsgheaders.RequestMessage; import com.sun.corba.se.impl.protocol.giopmsgheaders.RequestMessage_1_0 ; import com.sun.corba.se.impl.protocol.giopmsgheaders.RequestMessage_1_1 ; import com.sun.corba.se.impl.protocol.giopmsgheaders.RequestMessage_1_2 ; // REVISIT: make sure no memory leaks in client/server request/reply maps. // REVISIT: normalize requestHeader, replyHeader, messageHeader. /** * @author Harold Carr */ public class CorbaMessageMediatorImpl implements CorbaMessageMediator, CorbaProtocolHandler, MessageHandler { protected ORB orb; protected ORBUtilSystemException wrapper ; protected InterceptorsSystemException interceptorWrapper ; protected CorbaContactInfo contactInfo; protected CorbaConnection connection; protected short addrDisposition; protected CDROutputObject outputObject; protected CDRInputObject inputObject; protected Message messageHeader; protected RequestMessage requestHeader; protected LocateReplyOrReplyMessage replyHeader; protected String replyExceptionDetailMessage; protected IOR replyIOR; protected Integer requestIdInteger; protected Message dispatchHeader; protected ByteBuffer dispatchByteBuffer; protected byte streamFormatVersion; protected boolean streamFormatVersionSet = false; protected org.omg.CORBA.Request diiRequest; protected boolean cancelRequestAlreadySent = false; protected ProtocolHandler protocolHandler; protected boolean _executeReturnServantInResponseConstructor = false; protected boolean _executeRemoveThreadInfoInResponseConstructor = false; protected boolean _executePIInResponseConstructor = false; // // Client-side constructor. // public CorbaMessageMediatorImpl(ORB orb, ContactInfo contactInfo, Connection connection, GIOPVersion giopVersion, IOR ior, int requestId, short addrDisposition, String operationName, boolean isOneWay) { this( orb, connection ) ; this.contactInfo = (CorbaContactInfo) contactInfo; this.addrDisposition = addrDisposition; streamFormatVersion = getStreamFormatVersionForThisRequest( ((CorbaContactInfo)this.contactInfo).getEffectiveTargetIOR(), giopVersion); streamFormatVersionSet = true; requestHeader = (RequestMessage) MessageBase.createRequest( this.orb, giopVersion, ORBUtility.getEncodingVersion(orb, ior), requestId, !isOneWay, ((CorbaContactInfo)this.contactInfo).getEffectiveTargetIOR(), this.addrDisposition, operationName, new ServiceContexts(orb), null); } // // Acceptor constructor. // public CorbaMessageMediatorImpl(ORB orb, Connection connection) { this.orb = orb; this.connection = (CorbaConnection)connection; this.wrapper = ORBUtilSystemException.get( orb, CORBALogDomains.RPC_PROTOCOL ) ; this.interceptorWrapper = InterceptorsSystemException.get( orb, CORBALogDomains.RPC_PROTOCOL ) ; } // // Dispatcher constructor. // // Note: in some cases (e.g., a reply message) this message // mediator will only be used for dispatch. Then the original // request side mediator will take over. public CorbaMessageMediatorImpl(ORB orb, CorbaConnection connection, Message dispatchHeader, ByteBuffer byteBuffer) { this( orb, connection ) ; this.dispatchHeader = dispatchHeader; this.dispatchByteBuffer = byteBuffer; } //////////////////////////////////////////////////// // // MessageMediator // public Broker getBroker() { return orb; } public ContactInfo getContactInfo() { return contactInfo; } public Connection getConnection() { return connection; } public void initializeMessage() { getRequestHeader().write(outputObject); } public void finishSendingRequest() { // REVISIT: probably move logic in outputObject to here. outputObject.finishSendingMessage(); } public InputObject waitForResponse() { if (getRequestHeader().isResponseExpected()) { return connection.waitForResponse(this); } return null; } public void setOutputObject(OutputObject outputObject) { this.outputObject = (CDROutputObject) outputObject; } public OutputObject getOutputObject() { return outputObject; } public void setInputObject(InputObject inputObject) { this.inputObject = (CDRInputObject) inputObject; } public InputObject getInputObject() { return inputObject; } //////////////////////////////////////////////////// // // CorbaMessageMediator // public void setReplyHeader(LocateReplyOrReplyMessage header) { this.replyHeader = header; this.replyIOR = header.getIOR(); // REVISIT - need separate field? } public LocateReplyMessage getLocateReplyHeader() { return (LocateReplyMessage) replyHeader; } public ReplyMessage getReplyHeader() { return (ReplyMessage) replyHeader; } public void setReplyExceptionDetailMessage(String message) { replyExceptionDetailMessage = message; } public RequestMessage getRequestHeader() { return requestHeader; } public GIOPVersion getGIOPVersion() { if (messageHeader != null) { return messageHeader.getGIOPVersion(); } return getRequestHeader().getGIOPVersion(); } public byte getEncodingVersion() { if (messageHeader != null) { return messageHeader.getEncodingVersion(); } return getRequestHeader().getEncodingVersion(); } public int getRequestId() { return getRequestHeader().getRequestId(); } public Integer getRequestIdInteger() { if (requestIdInteger == null) { requestIdInteger = new Integer(getRequestHeader().getRequestId()); } return requestIdInteger; } public boolean isOneWay() { return ! getRequestHeader().isResponseExpected(); } public short getAddrDisposition() { return addrDisposition; } public String getOperationName() { return getRequestHeader().getOperation(); } public ServiceContexts getRequestServiceContexts() { return getRequestHeader().getServiceContexts(); } public ServiceContexts getReplyServiceContexts() { return getReplyHeader().getServiceContexts(); } public void sendCancelRequestIfFinalFragmentNotSent() { if ((!sentFullMessage()) && sentFragment() && (!cancelRequestAlreadySent)) { try { if (orb.subcontractDebugFlag) { dprint(".sendCancelRequestIfFinalFragmentNotSent->: " + opAndId(this)); } connection.sendCancelRequestWithLock(getGIOPVersion(), getRequestId()); // Case: first a location forward, then a marshaling // exception (e.g., non-serializable object). Only // send cancel once. cancelRequestAlreadySent = true; } catch (IOException e) { if (orb.subcontractDebugFlag) { dprint(".sendCancelRequestIfFinalFragmentNotSent: !ERROR : " + opAndId(this), e); } // REVISIT: we could attempt to send a final incomplete // fragment in this case. throw interceptorWrapper.ioexceptionDuringCancelRequest( CompletionStatus.COMPLETED_MAYBE, e ); } finally { if (orb.subcontractDebugFlag) { dprint(".sendCancelRequestIfFinalFragmentNotSent<-: " + opAndId(this)); } } } } public boolean sentFullMessage() { return outputObject.getBufferManager().sentFullMessage(); } public boolean sentFragment() { return outputObject.getBufferManager().sentFragment(); } public void setDIIInfo(org.omg.CORBA.Request diiRequest) { this.diiRequest = diiRequest; } public boolean isDIIRequest() { return diiRequest != null; } public Exception unmarshalDIIUserException(String repoId, InputStream is) { if (! isDIIRequest()) { return null; } ExceptionList _exceptions = diiRequest.exceptions(); try { // Find the typecode for the exception for (int i=0; i<_exceptions.count() ; i++) { TypeCode tc = _exceptions.item(i); if ( tc.id().equals(repoId) ) { // Since we dont have the actual user exception // class, the spec says we have to create an // UnknownUserException and put it in the // environment. Any eany = orb.create_any(); eany.read_value(is, (TypeCode)tc); return new UnknownUserException(eany); } } } catch (Exception b) { throw wrapper.unexpectedDiiException(b); } // must be a truly unknown exception return wrapper.unknownCorbaExc( CompletionStatus.COMPLETED_MAYBE); } public void setDIIException(Exception exception) { diiRequest.env().exception(exception); } public void handleDIIReply(InputStream inputStream) { if (! isDIIRequest()) { return; } ((RequestImpl)diiRequest).unmarshalReply(inputStream); } public Message getDispatchHeader() { return dispatchHeader; } public void setDispatchHeader(Message msg) { dispatchHeader = msg; } public ByteBuffer getDispatchBuffer() { return dispatchByteBuffer; } public void setDispatchBuffer(ByteBuffer byteBuffer) { dispatchByteBuffer = byteBuffer; } public int getThreadPoolToUse() { int poolToUse = 0; Message msg = getDispatchHeader(); // A null msg should never happen. But, we'll be // defensive just in case. if (msg != null) { poolToUse = msg.getThreadPoolToUse(); } return poolToUse; } public byte getStreamFormatVersion() { // REVISIT: ContactInfo/Acceptor output object factories // just use this. Maybe need to distinguish: // createOutputObjectForRequest // createOutputObjectForReply // then do getStreamFormatVersionForRequest/ForReply here. if (streamFormatVersionSet) { return streamFormatVersion; } return getStreamFormatVersionForReply(); } /** * If the RMI-IIOP maximum stream format version service context * is present, it indicates the maximum stream format version we * could use for the reply. If it isn't present, the default is * 2 for GIOP 1.3 or greater, 1 for lower. * * This is only sent on requests. Clients can find out the * server's maximum by looking for a tagged component in the IOR. */ public byte getStreamFormatVersionForReply() { // NOTE: The request service contexts may indicate the max. ServiceContexts svc = getRequestServiceContexts(); MaxStreamFormatVersionServiceContext msfvsc = (MaxStreamFormatVersionServiceContext)svc.get( MaxStreamFormatVersionServiceContext.SERVICE_CONTEXT_ID); if (msfvsc != null) { byte localMaxVersion = ORBUtility.getMaxStreamFormatVersion(); byte remoteMaxVersion = msfvsc.getMaximumStreamFormatVersion(); return (byte)Math.min(localMaxVersion, remoteMaxVersion); } else { // Defaults to 1 for GIOP 1.2 or less, 2 for // GIOP 1.3 or higher. if (getGIOPVersion().lessThan(GIOPVersion.V1_3)) return ORBConstants.STREAM_FORMAT_VERSION_1; else return ORBConstants.STREAM_FORMAT_VERSION_2; } } public boolean isSystemExceptionReply() { return replyHeader.getReplyStatus() == ReplyMessage.SYSTEM_EXCEPTION; } public boolean isUserExceptionReply() { return replyHeader.getReplyStatus() == ReplyMessage.USER_EXCEPTION; } public boolean isLocationForwardReply() { return ( (replyHeader.getReplyStatus() == ReplyMessage.LOCATION_FORWARD) || (replyHeader.getReplyStatus() == ReplyMessage.LOCATION_FORWARD_PERM) ); //return replyHeader.getReplyStatus() == ReplyMessage.LOCATION_FORWARD; } public boolean isDifferentAddrDispositionRequestedReply() { return replyHeader.getReplyStatus() == ReplyMessage.NEEDS_ADDRESSING_MODE; } public short getAddrDispositionReply() { return replyHeader.getAddrDisposition(); } public IOR getForwardedIOR() { return replyHeader.getIOR(); } public SystemException getSystemExceptionReply() { return replyHeader.getSystemException(replyExceptionDetailMessage); } //////////////////////////////////////////////////// // // Used by server side. // public ObjectKey getObjectKey() { return getRequestHeader().getObjectKey(); } public void setProtocolHandler(CorbaProtocolHandler protocolHandler) { throw wrapper.methodShouldNotBeCalled() ; } public CorbaProtocolHandler getProtocolHandler() { // REVISIT: should look up in orb registry. return this; } //////////////////////////////////////////////////// // // ResponseHandler // public org.omg.CORBA.portable.OutputStream createReply() { // Note: relies on side-effect of setting mediator output field. // REVISIT - cast - need interface getProtocolHandler().createResponse(this, (ServiceContexts) null); return (OutputStream) getOutputObject(); } public org.omg.CORBA.portable.OutputStream createExceptionReply() { // Note: relies on side-effect of setting mediator output field. // REVISIT - cast - need interface getProtocolHandler().createUserExceptionResponse(this, (ServiceContexts) null); return (OutputStream) getOutputObject(); } public boolean executeReturnServantInResponseConstructor() { return _executeReturnServantInResponseConstructor; } public void setExecuteReturnServantInResponseConstructor(boolean b) { _executeReturnServantInResponseConstructor = b; } public boolean executeRemoveThreadInfoInResponseConstructor() { return _executeRemoveThreadInfoInResponseConstructor; } public void setExecuteRemoveThreadInfoInResponseConstructor(boolean b) { _executeRemoveThreadInfoInResponseConstructor = b; } public boolean executePIInResponseConstructor() { return _executePIInResponseConstructor; } public void setExecutePIInResponseConstructor( boolean b ) { _executePIInResponseConstructor = b; } private byte getStreamFormatVersionForThisRequest(IOR ior, GIOPVersion giopVersion) { byte localMaxVersion = ORBUtility.getMaxStreamFormatVersion(); IOR effectiveTargetIOR = ((CorbaContactInfo)this.contactInfo).getEffectiveTargetIOR(); IIOPProfileTemplate temp = (IIOPProfileTemplate)effectiveTargetIOR.getProfile().getTaggedProfileTemplate(); Iterator iter = temp.iteratorById(TAG_RMI_CUSTOM_MAX_STREAM_FORMAT.value); if (!iter.hasNext()) { // Didn't have the max stream format version tagged // component. if (giopVersion.lessThan(GIOPVersion.V1_3)) return ORBConstants.STREAM_FORMAT_VERSION_1; else return ORBConstants.STREAM_FORMAT_VERSION_2; } byte remoteMaxVersion = ((MaxStreamFormatVersionComponent)iter.next()).getMaxStreamFormatVersion(); return (byte)Math.min(localMaxVersion, remoteMaxVersion); } //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // REVISIT - This could be a separate implementation object looked // up in a registry. However it needs some state in the message // mediator so combine for now. protected boolean isThreadDone = false; //////////////////////////////////////////////////// // // pept.protocol.ProtocolHandler // public boolean handleRequest(MessageMediator messageMediator) { try { dispatchHeader.callback(this); } catch (IOException e) { // REVISIT - this should be handled internally. ; } return isThreadDone; } //////////////////////////////////////////////////// // // iiop.messages.MessageHandler // private void setWorkThenPoolOrResumeSelect(Message header) { if (getConnection().getEventHandler().shouldUseSelectThreadToWait()) { resumeSelect(header); } else { // Leader/Follower when using reader thread. // When this thread is done working it will go back in pool. isThreadDone = true; // First unregister current registration. orb.getTransportManager().getSelector(0) .unregisterForEvent(getConnection().getEventHandler()); // Have another thread become the reader. orb.getTransportManager().getSelector(0) .registerForEvent(getConnection().getEventHandler()); } } private void setWorkThenReadOrResumeSelect(Message header) { if (getConnection().getEventHandler().shouldUseSelectThreadToWait()) { resumeSelect(header); } else { // When using reader thread then wen this thread is // done working it will continue reading. isThreadDone = false; } } private void resumeSelect(Message header) { // NOTE: VERY IMPORTANT: // Only participate in select after getting to the point // that proper serialization of fragments is ensured. if (transportDebug()) { dprint(".resumeSelect:->"); // REVISIT: not-OO: String requestId = "?"; if (header instanceof RequestMessage) { requestId = new Integer(((RequestMessage)header) .getRequestId()).toString(); } else if (header instanceof ReplyMessage) { requestId = new Integer(((ReplyMessage)header) .getRequestId()).toString(); } else if (header instanceof FragmentMessage_1_2) { requestId = new Integer(((FragmentMessage_1_2)header) .getRequestId()).toString(); } dprint(".resumeSelect: id/" + requestId + " " + getConnection() ); } // IMPORTANT: To avoid bug (4953599), we force the Thread that does the NIO select // to also do the enable/disable of Ops using SelectionKey.interestOps(Ops of Interest). // Otherwise, the SelectionKey.interestOps(Ops of Interest) may block indefinitely in // this thread. EventHandler eventHandler = getConnection().getEventHandler(); orb.getTransportManager().getSelector(0).registerInterestOps(eventHandler); if (transportDebug()) { dprint(".resumeSelect:<-"); } } private void setInputObject() { // REVISIT: refactor createInputObject (and createMessageMediator) // into base PlugInFactory. Get via connection (either ContactInfo // or Acceptor). if (getConnection().getContactInfo() != null) { inputObject = (CDRInputObject) getConnection().getContactInfo() .createInputObject(orb, this); } else if (getConnection().getAcceptor() != null) { inputObject = (CDRInputObject) getConnection().getAcceptor() .createInputObject(orb, this); } else { throw new RuntimeException("CorbaMessageMediatorImpl.setInputObject"); } inputObject.setMessageMediator(this); setInputObject(inputObject); } private void signalResponseReceived() { // This will end up using the MessageMediator associated with // the original request instead of the current mediator (which // need to be constructed to hold the dispatchBuffer and connection). connection.getResponseWaitingRoom() .responseReceived((InputObject)inputObject); } // This handles message types for which we don't create classes. public void handleInput(Message header) throws IOException { try { messageHeader = header; if (transportDebug()) dprint(".handleInput->: " + MessageBase.typeToString(header.getType())); setWorkThenReadOrResumeSelect(header); switch(header.getType()) { case Message.GIOPCloseConnection: if (transportDebug()) { dprint(".handleInput: CloseConnection: purging"); } connection.purgeCalls(wrapper.connectionRebind(), true, false); break; case Message.GIOPMessageError: if (transportDebug()) { dprint(".handleInput: MessageError: purging"); } connection.purgeCalls(wrapper.recvMsgError(), true, false); break; default: if (transportDebug()) { dprint(".handleInput: ERROR: " + MessageBase.typeToString(header.getType())); } throw wrapper.badGiopRequestType() ; } releaseByteBufferToPool(); } finally { if (transportDebug()) { dprint(".handleInput<-: " + MessageBase.typeToString(header.getType())); } } } public void handleInput(RequestMessage_1_0 header) throws IOException { try { if (transportDebug()) dprint(".REQUEST 1.0->: " + header); try { messageHeader = requestHeader = (RequestMessage) header; setInputObject(); } finally { setWorkThenPoolOrResumeSelect(header); } getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".REQUEST 1.0: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".REQUEST 1.0<-: " + header); } } public void handleInput(RequestMessage_1_1 header) throws IOException { try { if (transportDebug()) dprint(".REQUEST 1.1->: " + header); try { messageHeader = requestHeader = (RequestMessage) header; setInputObject(); connection.serverRequest_1_1_Put(this); } finally { setWorkThenPoolOrResumeSelect(header); } getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".REQUEST 1.1: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".REQUEST 1.1<-: " + header); } } // REVISIT: this is identical to 1_0 except for fragment part. public void handleInput(RequestMessage_1_2 header) throws IOException { try { try { messageHeader = requestHeader = (RequestMessage) header; header.unmarshalRequestID(dispatchByteBuffer); setInputObject(); if (transportDebug()) dprint(".REQUEST 1.2->: id/" + header.getRequestId() + ": " + header); // NOTE: in the old code this used to be done conditionally: // if (header.moreFragmentsToFollow()). // Now we always put it in. We take it out when // the response is done. // This must happen now so if a header is fragmented the stream // may be found. connection.serverRequestMapPut(header.getRequestId(), this); } finally { // Leader/Follower. // Note: This *MUST* come after putting stream in above map // since the header may be fragmented and you do not want to // start reading again until the map above is set. setWorkThenPoolOrResumeSelect(header); } //inputObject.unmarshalHeader(); // done in subcontract. getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".REQUEST 1.2: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { connection.serverRequestMapRemove(header.getRequestId()); if (transportDebug()) dprint(".REQUEST 1.2<-: id/" + header.getRequestId() + ": " + header); } } public void handleInput(ReplyMessage_1_0 header) throws IOException { try { try { if (transportDebug()) dprint(".REPLY 1.0->: " + header); messageHeader = replyHeader = (ReplyMessage) header; setInputObject(); // REVISIT: this should be done by waiting thread. inputObject.unmarshalHeader(); signalResponseReceived(); } finally{ setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug())dprint(".REPLY 1.0: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".REPLY 1.0<-: " + header); } } public void handleInput(ReplyMessage_1_1 header) throws IOException { try { if (transportDebug()) dprint(".REPLY 1.1->: " + header); messageHeader = replyHeader = (ReplyMessage) header; setInputObject(); if (header.moreFragmentsToFollow()) { // More fragments are coming to complete this reply, so keep // a reference to the InputStream so we can add the fragments connection.clientReply_1_1_Put(this); // In 1.1, we can't assume that we have the request ID in the // first fragment. Thus, another thread is used // to be the reader while this thread unmarshals // the extended header and wakes up the client thread. setWorkThenPoolOrResumeSelect(header); // REVISIT - error handling. // This must be done now. inputObject.unmarshalHeader(); signalResponseReceived(); } else { // Not fragmented, therefore we know the request // ID is here. Thus, we can unmarshal the extended header // and wake up the client thread without using a third // thread as above. // REVISIT - error handling during unmarshal. // This must be done now to get the request id. inputObject.unmarshalHeader(); signalResponseReceived(); setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".REPLY 1.1: !!ERROR!!: " + header); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".REPLY 1.1<-: " + header); } } public void handleInput(ReplyMessage_1_2 header) throws IOException { try { try { messageHeader = replyHeader = (ReplyMessage) header; // We know that the request ID is in the first fragment header.unmarshalRequestID(dispatchByteBuffer); if (transportDebug()) { dprint(".REPLY 1.2->: id/" + + header.getRequestId() + ": more?: " + header.moreFragmentsToFollow() + ": " + header); } setInputObject(); signalResponseReceived(); } finally { setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".REPLY 1.2: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".REPLY 1.2<-: id/" + header.getRequestId() + ": " + header); } } public void handleInput(LocateRequestMessage_1_0 header) throws IOException { try { if (transportDebug()) dprint(".LOCATE_REQUEST 1.0->: " + header); try { messageHeader = header; setInputObject(); } finally { setWorkThenPoolOrResumeSelect(header); } getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REQUEST 1.0: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REQUEST 1.0<-: " + header); } } public void handleInput(LocateRequestMessage_1_1 header) throws IOException { try { if (transportDebug()) dprint(".LOCATE_REQUEST 1.1->: " + header); try { messageHeader = header; setInputObject(); } finally { setWorkThenPoolOrResumeSelect(header); } getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REQUEST 1.1: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REQUEST 1.1<-:" + header); } } public void handleInput(LocateRequestMessage_1_2 header) throws IOException { try { try { messageHeader = header; header.unmarshalRequestID(dispatchByteBuffer); setInputObject(); if (transportDebug()) dprint(".LOCATE_REQUEST 1.2->: id/" + header.getRequestId() + ": " + header); if (header.moreFragmentsToFollow()) { connection.serverRequestMapPut(header.getRequestId(),this); } } finally { setWorkThenPoolOrResumeSelect(header); } getProtocolHandler().handleRequest(header, this); } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REQUEST 1.2: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REQUEST 1.2<-: id/" + header.getRequestId() + ": " + header); } } public void handleInput(LocateReplyMessage_1_0 header) throws IOException { try { if (transportDebug()) dprint(".LOCATE_REPLY 1.0->:" + header); try { messageHeader = header; setInputObject(); inputObject.unmarshalHeader(); // REVISIT Put in subcontract. signalResponseReceived(); } finally { setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REPLY 1.0: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REPLY 1.0<-: " + header); } } public void handleInput(LocateReplyMessage_1_1 header) throws IOException { try { if (transportDebug()) dprint(".LOCATE_REPLY 1.1->: " + header); try { messageHeader = header; setInputObject(); // Fragmented LocateReplies are not allowed in 1.1. inputObject.unmarshalHeader(); signalResponseReceived(); } finally { setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REPLY 1.1: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REPLY 1.1<-: " + header); } } public void handleInput(LocateReplyMessage_1_2 header) throws IOException { try { try { messageHeader = header; // No need to put in client reply map - already there. header.unmarshalRequestID(dispatchByteBuffer); setInputObject(); if (transportDebug()) dprint(".LOCATE_REPLY 1.2->: id/" + header.getRequestId() + ": " + header); signalResponseReceived(); } finally { setWorkThenPoolOrResumeSelect(header); // REVISIT } } catch (Throwable t) { if (transportDebug()) dprint(".LOCATE_REPLY 1.2: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".LOCATE_REPLY 1.2<-: id/" + header.getRequestId() + ": " + header); } } public void handleInput(FragmentMessage_1_1 header) throws IOException { try { if (transportDebug()) { dprint(".FRAGMENT 1.1->: " + "more?: " + header.moreFragmentsToFollow() + ": " + header); } try { messageHeader = header; MessageMediator mediator = null; CDRInputObject inputObject = null; if (connection.isServer()) { mediator = connection.serverRequest_1_1_Get(); } else { mediator = connection.clientReply_1_1_Get(); } if (mediator != null) { inputObject = (CDRInputObject) mediator.getInputObject(); } // If no input stream available, then discard the fragment. // This can happen: // 1. if a fragment message is received prior to receiving // the original request/reply message. Very unlikely. // 2. if a fragment message is received after the // reply has been sent (early replies) // Note: In the case of early replies, the fragments received // during the request processing (which are never unmarshaled), // will eventually be discarded by the GC. if (inputObject == null) { if (transportDebug()) dprint(".FRAGMENT 1.1: ++++DISCARDING++++: " + header); // need to release dispatchByteBuffer to pool if // we are discarding releaseByteBufferToPool(); return; } inputObject.getBufferManager() .processFragment(dispatchByteBuffer, header); if (! header.moreFragmentsToFollow()) { if (connection.isServer()) { connection.serverRequest_1_1_Remove(); } else { connection.clientReply_1_1_Remove(); } } } finally { // NOTE: This *must* come after queing the fragment // when using the selector to ensure fragments stay in order. setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".FRAGMENT 1.1: !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".FRAGMENT 1.1<-: " + header); } } public void handleInput(FragmentMessage_1_2 header) throws IOException { try { try { messageHeader = header; // Note: We know it's a 1.2 fragment, we have the data, but // we need the IIOPInputStream instance to unmarshal the // request ID... but we need the request ID to get the // IIOPInputStream instance. So we peek at the raw bytes. header.unmarshalRequestID(dispatchByteBuffer); if (transportDebug()) { dprint(".FRAGMENT 1.2->: id/" + header.getRequestId() + ": more?: " + header.moreFragmentsToFollow() + ": " + header); } MessageMediator mediator = null; InputObject inputObject = null; if (connection.isServer()) { mediator = connection.serverRequestMapGet(header.getRequestId()); } else { mediator = connection.clientRequestMapGet(header.getRequestId()); } if (mediator != null) { inputObject = mediator.getInputObject(); } // See 1.1 comments. if (inputObject == null) { if (transportDebug()) { dprint(".FRAGMENT 1.2: id/" + header.getRequestId() + ": ++++DISCARDING++++: " + header); } // need to release dispatchByteBuffer to pool if // we are discarding releaseByteBufferToPool(); return; } ((CDRInputObject)inputObject) .getBufferManager().processFragment( dispatchByteBuffer, header); // REVISIT: but if it is a server don't you have to remove the // stream from the map? if (! connection.isServer()) { /* REVISIT * No need to do anything. * Should we mark that last was received? if (! header.moreFragmentsToFollow()) { // Last fragment. } */ } } finally { // NOTE: This *must* come after queing the fragment // when using the selector to ensure fragments stay in order. setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".FRAGMENT 1.2: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".FRAGMENT 1.2<-: id/" + header.getRequestId() + ": " + header); } } public void handleInput(CancelRequestMessage header) throws IOException { try { try { messageHeader = header; setInputObject(); // REVISIT: Move these two to subcontract. inputObject.unmarshalHeader(); if (transportDebug()) dprint(".CANCEL->: id/" + header.getRequestId() + ": " + header.getGIOPVersion() + ": " + header); processCancelRequest(header.getRequestId()); releaseByteBufferToPool(); } finally { setWorkThenReadOrResumeSelect(header); } } catch (Throwable t) { if (transportDebug()) dprint(".CANCEL: id/" + header.getRequestId() + ": !!ERROR!!: " + header, t); // Mask the exception from thread.; } finally { if (transportDebug()) dprint(".CANCEL<-: id/" + header.getRequestId() + ": " + header.getGIOPVersion() + ": " + header); } } private void throwNotImplemented() { isThreadDone = false; throwNotImplemented(""); } private void throwNotImplemented(String msg) { throw new RuntimeException("CorbaMessageMediatorImpl: not implemented " + msg); } private void dprint(String msg, Throwable t) { dprint(msg); t.printStackTrace(System.out); } private void dprint(String msg) { ORBUtility.dprint("CorbaMessageMediatorImpl", msg); } protected String opAndId(CorbaMessageMediator mediator) { return ORBUtility.operationNameAndRequestId(mediator); } private boolean transportDebug() { return orb.transportDebugFlag; } // REVISIT: move this to subcontract (but both client and server need it). private final void processCancelRequest(int cancelReqId) { // The GIOP version of CancelRequest does not matter, since // CancelRequest_1_0 could be sent to cancel a request which // has a different GIOP version. /* * CancelRequest processing logic : * * - find the request with matching requestId * * - call cancelProcessing() in BufferManagerRead [BMR] * * - the hope is that worker thread would call BMR.underflow() * to wait for more fragments to come in. When BMR.underflow() is * called, if a CancelRequest had already arrived, * the worker thread would throw ThreadDeath, * else the thread would wait to be notified of the * arrival of a new fragment or CancelRequest. Upon notification, * the woken up thread would check to see if a CancelRequest had * arrived and if so throw a ThreadDeath or it will continue to * process the received fragment. * * - if all the fragments had been received prior to CancelRequest * then the worker thread would never block in BMR.underflow(). * So, setting the abort flag in BMR has no effect. The request * processing will complete normally. * * - in the case where the server has received enough fragments to * start processing the request and the server sends out * an early reply. In such a case if the CancelRequest arrives * after the reply has been sent, it has no effect. */ if (!connection.isServer()) { return; // we do not support bi-directional giop yet, ignore. } // Try to get hold of the InputStream buffer. // In the case of 1.0 requests there is no way to get hold of // InputStream. Try out the 1.1 and 1.2 cases. // was the request 1.2 ? MessageMediator mediator = connection.serverRequestMapGet(cancelReqId); int requestId ; if (mediator == null) { // was the request 1.1 ? mediator = connection.serverRequest_1_1_Get(); if (mediator == null) { // XXX log this! // either the request was 1.0 // or an early reply has already been sent // or request processing is over // or its a spurious CancelRequest return; // do nothing. } requestId = ((CorbaMessageMediator) mediator).getRequestId(); if (requestId != cancelReqId) { // A spurious 1.1 CancelRequest has been received. // XXX log this! return; // do nothing } if (requestId == 0) { // special case // XXX log this // this means that // 1. the 1.1 requests' requestId has not been received // i.e., a CancelRequest was received even before the // 1.1 request was received. The spec disallows this. // 2. or the 1.1 request has a requestId 0. // // It is a little tricky to distinguish these two. So, be // conservative and do not cancel the request. Downside is that // 1.1 requests with requestId of 0 will never be cancelled. return; // do nothing } } else { requestId = ((CorbaMessageMediator) mediator).getRequestId(); } Message msg = ((CorbaMessageMediator)mediator).getRequestHeader(); if (msg.getType() != Message.GIOPRequest) { // Any mediator obtained here should only ever be for a GIOP // request. wrapper.badMessageTypeForCancel() ; } // At this point we have a valid message mediator that contains // a valid requestId. // at this point we have chosen a request to be cancelled. But we // do not know if the target object's method has been invoked or not. // Request input stream being available simply means that the request // processing is not over yet. simply set the abort flag in the // BMRS and hope that the worker thread would notice it (this can // happen only if the request stream is being unmarshalled and the // target's method has not been invoked yet). This guarantees // that the requests which have been dispatched to the // target's method will never be cancelled. BufferManagerReadStream bufferManager = (BufferManagerReadStream) ((CDRInputObject)mediator.getInputObject()).getBufferManager(); bufferManager.cancelProcessing(cancelReqId); } //////////////////////////////////////////////////// // // spi.protocol.CorbaProtocolHandler // public void handleRequest(RequestMessage msg, CorbaMessageMediator messageMediator) { try { beginRequest(messageMediator); try { handleRequestRequest(messageMediator); if (messageMediator.isOneWay()) { return; } } catch (Throwable t) { if (messageMediator.isOneWay()) { return; } handleThrowableDuringServerDispatch( messageMediator, t, CompletionStatus.COMPLETED_MAYBE); } sendResponse(messageMediator); } catch (Throwable t) { dispatchError(messageMediator, "RequestMessage", t); } finally { endRequest(messageMediator); } } public void handleRequest(LocateRequestMessage msg, CorbaMessageMediator messageMediator) { try { beginRequest(messageMediator); try { handleLocateRequest(messageMediator); } catch (Throwable t) { handleThrowableDuringServerDispatch( messageMediator, t, CompletionStatus.COMPLETED_MAYBE); } sendResponse(messageMediator); } catch (Throwable t) { dispatchError(messageMediator, "LocateRequestMessage", t); } finally { endRequest(messageMediator); } } private void beginRequest(CorbaMessageMediator messageMediator) { ORB orb = (ORB) messageMediator.getBroker(); if (orb.subcontractDebugFlag) { dprint(".handleRequest->:"); } connection.serverRequestProcessingBegins(); } private void dispatchError(CorbaMessageMediator messageMediator, String msg, Throwable t) { if (orb.subcontractDebugFlag) { dprint(".handleRequest: " + opAndId(messageMediator) + ": !!ERROR!!: " + msg, t); } // REVISIT - this makes hcks sendTwoObjects fail // messageMediator.getConnection().close(); } private void sendResponse(CorbaMessageMediator messageMediator) { if (orb.subcontractDebugFlag) { dprint(".handleRequest: " + opAndId(messageMediator) + ": sending response"); } // REVISIT - type and location CDROutputObject outputObject = (CDROutputObject) messageMediator.getOutputObject(); if (outputObject != null) { // REVISIT - can be null for TRANSIENT below. outputObject.finishSendingMessage(); } } private void endRequest(CorbaMessageMediator messageMediator) { ORB orb = (ORB) messageMediator.getBroker(); if (orb.subcontractDebugFlag) { dprint(".handleRequest<-: " + opAndId(messageMediator)); } // release NIO ByteBuffers to ByteBufferPool try { OutputObject outputObj = messageMediator.getOutputObject(); if (outputObj != null) { outputObj.close(); } InputObject inputObj = messageMediator.getInputObject(); if (inputObj != null) { inputObj.close(); } } catch (IOException ex) { // Given what close() does, this catch shouldn't ever happen. // See CDRInput/OutputObject.close() for more info. // It also won't result in a Corba error if an IOException happens. if (orb.subcontractDebugFlag) { dprint(".endRequest: IOException:" + ex.getMessage(), ex); } } finally { ((CorbaConnection)messageMediator.getConnection()).serverRequestProcessingEnds(); } } protected void handleRequestRequest(CorbaMessageMediator messageMediator) { // Does nothing if already unmarshaled. ((CDRInputObject)messageMediator.getInputObject()).unmarshalHeader(); ORB orb = (ORB)messageMediator.getBroker(); synchronized (orb) { orb.checkShutdownState(); } ObjectKey okey = messageMediator.getObjectKey(); if (orb.subcontractDebugFlag) { ObjectKeyTemplate oktemp = okey.getTemplate() ; dprint( ".handleRequest: " + opAndId(messageMediator) + ": dispatching to scid: " + oktemp.getSubcontractId()); } CorbaServerRequestDispatcher sc = okey.getServerRequestDispatcher(orb); if (orb.subcontractDebugFlag) { dprint(".handleRequest: " + opAndId(messageMediator) + ": dispatching to sc: " + sc); } if (sc == null) { throw wrapper.noServerScInDispatch() ; } // NOTE: // This is necessary so mediator can act as ResponseHandler // and pass necessary info to response constructors located // in the subcontract. // REVISIT - same class right now. //messageMediator.setProtocolHandler(this); try { orb.startingDispatch(); sc.dispatch(messageMediator); } finally { orb.finishedDispatch(); } } protected void handleLocateRequest(CorbaMessageMediator messageMediator) { ORB orb = (ORB)messageMediator.getBroker(); LocateRequestMessage msg = (LocateRequestMessage) messageMediator.getDispatchHeader(); IOR ior = null; LocateReplyMessage reply = null; short addrDisp = -1; try { ((CDRInputObject)messageMediator.getInputObject()).unmarshalHeader(); CorbaServerRequestDispatcher sc = msg.getObjectKey().getServerRequestDispatcher( orb ) ; if (sc == null) { return; } ior = sc.locate(msg.getObjectKey()); if ( ior == null ) { reply = MessageBase.createLocateReply( orb, msg.getGIOPVersion(), msg.getEncodingVersion(), msg.getRequestId(), LocateReplyMessage.OBJECT_HERE, null); } else { reply = MessageBase.createLocateReply( orb, msg.getGIOPVersion(), msg.getEncodingVersion(), msg.getRequestId(), LocateReplyMessage.OBJECT_FORWARD, ior); } // REVISIT: Should we catch SystemExceptions? } catch (AddressingDispositionException ex) { // create a response containing the expected target // addressing disposition. reply = MessageBase.createLocateReply( orb, msg.getGIOPVersion(), msg.getEncodingVersion(), msg.getRequestId(), LocateReplyMessage.LOC_NEEDS_ADDRESSING_MODE, null); addrDisp = ex.expectedAddrDisp(); } catch (RequestCanceledException ex) { return; // no need to send reply } catch ( Exception ex ) { // REVISIT If exception is not OBJECT_NOT_EXIST, it should // have a different reply // This handles OBJECT_NOT_EXIST exceptions thrown in // the subcontract or obj manager. Send back UNKNOWN_OBJECT. reply = MessageBase.createLocateReply( orb, msg.getGIOPVersion(), msg.getEncodingVersion(), msg.getRequestId(), LocateReplyMessage.UNKNOWN_OBJECT, null); } CDROutputObject outputObject = createAppropriateOutputObject(messageMediator, msg, reply); messageMediator.setOutputObject(outputObject); outputObject.setMessageMediator(messageMediator); reply.write(outputObject); // outputObject.setMessage(reply); // REVISIT - not necessary if (ior != null) { ior.write(outputObject); } if (addrDisp != -1) { AddressingDispositionHelper.write(outputObject, addrDisp); } } private CDROutputObject createAppropriateOutputObject( CorbaMessageMediator messageMediator, Message msg, LocateReplyMessage reply) { CDROutputObject outputObject; if (msg.getGIOPVersion().lessThan(GIOPVersion.V1_2)) { // locate msgs 1.0 & 1.1 :=> grow, outputObject = sun.corba.OutputStreamFactory.newCDROutputObject( (ORB) messageMediator.getBroker(), this, GIOPVersion.V1_0, (CorbaConnection) messageMediator.getConnection(), reply, ORBConstants.STREAM_FORMAT_VERSION_1); } else { // 1.2 :=> stream outputObject = sun.corba.OutputStreamFactory.newCDROutputObject( (ORB) messageMediator.getBroker(), messageMediator, reply, ORBConstants.STREAM_FORMAT_VERSION_1); } return outputObject; } public void handleThrowableDuringServerDispatch( CorbaMessageMediator messageMediator, Throwable throwable, CompletionStatus completionStatus) { if (((ORB)messageMediator.getBroker()).subcontractDebugFlag) { dprint(".handleThrowableDuringServerDispatch: " + opAndId(messageMediator) + ": " + throwable); } // If we haven't unmarshaled the header, we probably don't // have enough information to even send back a reply. // REVISIT // Cannot do this check. When target addressing disposition does // not match (during header unmarshaling) it throws an exception // to be handled here. /* if (! ((CDRInputObject)messageMediator.getInputObject()) .unmarshaledHeader()) { return; } */ handleThrowableDuringServerDispatch(messageMediator, throwable, completionStatus, 1); } // REVISIT - catch and ignore RequestCanceledException. protected void handleThrowableDuringServerDispatch( CorbaMessageMediator messageMediator, Throwable throwable, CompletionStatus completionStatus, int iteration) { if (iteration > 10) { if (((ORB)messageMediator.getBroker()).subcontractDebugFlag) { dprint(".handleThrowableDuringServerDispatch: " + opAndId(messageMediator) + ": cannot handle: " + throwable); } // REVISIT - should we close connection? RuntimeException rte = new RuntimeException("handleThrowableDuringServerDispatch: " + "cannot create response."); rte.initCause(throwable); throw rte; } try { if (throwable instanceof ForwardException) { ForwardException fex = (ForwardException)throwable ; createLocationForward( messageMediator, fex.getIOR(), null ) ; return; } if (throwable instanceof AddressingDispositionException) { handleAddressingDisposition( messageMediator, (AddressingDispositionException)throwable); return; } // Else. SystemException sex = convertThrowableToSystemException(throwable, completionStatus); createSystemExceptionResponse(messageMediator, sex, null); return; } catch (Throwable throwable2) { // User code (e.g., postinvoke, interceptors) may change // the exception, so we end up back here. // Report the changed exception. handleThrowableDuringServerDispatch(messageMediator, throwable2, completionStatus, iteration + 1); return; } } protected SystemException convertThrowableToSystemException( Throwable throwable, CompletionStatus completionStatus) { if (throwable instanceof SystemException) { return (SystemException)throwable; } if (throwable instanceof RequestCanceledException) { // Reporting an exception response causes the // poa current stack, the interceptor stacks, etc. // to be balanced. It also notifies interceptors // that the request was cancelled. return wrapper.requestCanceled( throwable ) ; } // NOTE: We do not trap ThreadDeath above Throwable. // There is no reason to stop the thread. It is // just a worker thread. The ORB never throws // ThreadDeath. Client code may (e.g., in ServantManagers, // interceptors, or servants) but that should not // effect the ORB threads. So it is just handled // generically. // // Last resort. // If user code throws a non-SystemException report it generically. // return wrapper.runtimeexception( CompletionStatus.COMPLETED_MAYBE, throwable ) ; } protected void handleAddressingDisposition( CorbaMessageMediator messageMediator, AddressingDispositionException ex) { short addrDisp = -1; // from iiop.RequestProcessor. // Respond with expected target addressing disposition. switch (messageMediator.getRequestHeader().getType()) { case Message.GIOPRequest : ReplyMessage replyHeader = MessageBase.createReply( (ORB)messageMediator.getBroker(), messageMediator.getGIOPVersion(), messageMediator.getEncodingVersion(), messageMediator.getRequestId(), ReplyMessage.NEEDS_ADDRESSING_MODE, null, null); // REVISIT: via acceptor factory. CDROutputObject outputObject = sun.corba.OutputStreamFactory.newCDROutputObject( (ORB)messageMediator.getBroker(), this, messageMediator.getGIOPVersion(), (CorbaConnection)messageMediator.getConnection(), replyHeader, ORBConstants.STREAM_FORMAT_VERSION_1); messageMediator.setOutputObject(outputObject); outputObject.setMessageMediator(messageMediator); replyHeader.write(outputObject); AddressingDispositionHelper.write(outputObject, ex.expectedAddrDisp()); return; case Message.GIOPLocateRequest : LocateReplyMessage locateReplyHeader = MessageBase.createLocateReply( (ORB)messageMediator.getBroker(), messageMediator.getGIOPVersion(), messageMediator.getEncodingVersion(), messageMediator.getRequestId(), LocateReplyMessage.LOC_NEEDS_ADDRESSING_MODE, null); addrDisp = ex.expectedAddrDisp(); // REVISIT: via acceptor factory. outputObject = createAppropriateOutputObject(messageMediator, messageMediator.getRequestHeader(), locateReplyHeader); messageMediator.setOutputObject(outputObject); outputObject.setMessageMediator(messageMediator); locateReplyHeader.write(outputObject); IOR ior = null; if (ior != null) { ior.write(outputObject); } if (addrDisp != -1) { AddressingDispositionHelper.write(outputObject, addrDisp); } return; } } public CorbaMessageMediator createResponse( CorbaMessageMediator messageMediator, ServiceContexts svc) { // REVISIT: ignore service contexts during framework transition. // They are set in SubcontractResponseHandler to the wrong connection. // Then they would be set again here and a duplicate contexts // exception occurs. return createResponseHelper( messageMediator, getServiceContextsForReply(messageMediator, null)); } public CorbaMessageMediator createUserExceptionResponse( CorbaMessageMediator messageMediator, ServiceContexts svc) { // REVISIT - same as above return createResponseHelper( messageMediator, getServiceContextsForReply(messageMediator, null), true); } public CorbaMessageMediator createUnknownExceptionResponse( CorbaMessageMediator messageMediator, UnknownException ex) { // NOTE: This service context container gets augmented in // tail call. ServiceContexts contexts = null; SystemException sys = new UNKNOWN( 0, CompletionStatus.COMPLETED_MAYBE); contexts = new ServiceContexts( (ORB)messageMediator.getBroker() ); UEInfoServiceContext uei = new UEInfoServiceContext(sys); contexts.put( uei ) ; return createSystemExceptionResponse(messageMediator, sys, contexts); } public CorbaMessageMediator createSystemExceptionResponse( CorbaMessageMediator messageMediator, SystemException ex, ServiceContexts svc) { if (messageMediator.getConnection() != null) { // It is possible that fragments of response have already been // sent. Then an error may occur (e.g. marshaling error like // non serializable object). In that case it is too late // to send the exception. We just return the existing fragmented // stream here. This will cause an incomplete last fragment // to be sent. Then the other side will get a marshaling error // when attempting to unmarshal. // REVISIT: Impl - make interface method to do the following. CorbaMessageMediatorImpl mediator = (CorbaMessageMediatorImpl) ((CorbaConnection)messageMediator.getConnection()) .serverRequestMapGet(messageMediator.getRequestId()); OutputObject existingOutputObject = null; if (mediator != null) { existingOutputObject = mediator.getOutputObject(); } // REVISIT: need to think about messageMediator containing correct // pointer to output object. if (existingOutputObject != null && mediator.sentFragment() && ! mediator.sentFullMessage()) { return mediator; } } // Only do this if interceptors have been initialized on this request // and have not completed their lifecycle (otherwise the info stack // may be empty or have a different request's entry on top). if (messageMediator.executePIInResponseConstructor()) { // REVISIT: not necessary in framework now? // Inform Portable Interceptors of the SystemException. This is // required to be done here because the ending interception point // is called in the when creating the response below // but we do not currently write the SystemException into the // response until after the ending point is called. ((ORB)messageMediator.getBroker()).getPIHandler().setServerPIInfo( ex ); } if (((ORB)messageMediator.getBroker()).subcontractDebugFlag && ex != null) { dprint(".createSystemExceptionResponse: " + opAndId(messageMediator), ex); } ServiceContexts serviceContexts = getServiceContextsForReply(messageMediator, svc); // NOTE: We MUST add the service context before creating // the response since service contexts are written to the // stream when the response object is created. addExceptionDetailMessage(messageMediator, ex, serviceContexts); CorbaMessageMediator response = createResponseHelper(messageMediator, serviceContexts, false); // NOTE: From here on, it is too late to add more service contexts. // They have already been serialized to the stream (and maybe fragments // sent). ORBUtility.writeSystemException( ex, (OutputStream)response.getOutputObject()); return response; } private void addExceptionDetailMessage(CorbaMessageMediator mediator, SystemException ex, ServiceContexts serviceContexts) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintWriter pw = new PrintWriter(baos); ex.printStackTrace(pw); pw.flush(); // NOTE: you must flush or baos will be empty. EncapsOutputStream encapsOutputStream = sun.corba.OutputStreamFactory.newEncapsOutputStream((ORB)mediator.getBroker()); encapsOutputStream.putEndian(); encapsOutputStream.write_wstring(baos.toString()); UnknownServiceContext serviceContext = new UnknownServiceContext(ExceptionDetailMessage.value, encapsOutputStream.toByteArray()); serviceContexts.put(serviceContext); } public CorbaMessageMediator createLocationForward( CorbaMessageMediator messageMediator, IOR ior, ServiceContexts svc) { ReplyMessage reply = MessageBase.createReply( (ORB)messageMediator.getBroker(), messageMediator.getGIOPVersion(), messageMediator.getEncodingVersion(), messageMediator.getRequestId(), ReplyMessage.LOCATION_FORWARD, getServiceContextsForReply(messageMediator, svc), ior); return createResponseHelper(messageMediator, reply, ior); } protected CorbaMessageMediator createResponseHelper( CorbaMessageMediator messageMediator, ServiceContexts svc) { ReplyMessage message = MessageBase.createReply( (ORB)messageMediator.getBroker(), messageMediator.getGIOPVersion(), messageMediator.getEncodingVersion(), messageMediator.getRequestId(), ReplyMessage.NO_EXCEPTION, svc, null); return createResponseHelper(messageMediator, message, null); } protected CorbaMessageMediator createResponseHelper( CorbaMessageMediator messageMediator, ServiceContexts svc,boolean user) { ReplyMessage message = MessageBase.createReply( (ORB)messageMediator.getBroker(), messageMediator.getGIOPVersion(), messageMediator.getEncodingVersion(), messageMediator.getRequestId(), user ? ReplyMessage.USER_EXCEPTION : ReplyMessage.SYSTEM_EXCEPTION, svc, null); return createResponseHelper(messageMediator, message, null); } // REVISIT - IOR arg is ignored. protected CorbaMessageMediator createResponseHelper( CorbaMessageMediator messageMediator, ReplyMessage reply, IOR ior) { // REVISIT - these should be invoked from subcontract. runServantPostInvoke(messageMediator); runInterceptors(messageMediator, reply); runRemoveThreadInfo(messageMediator); if (((ORB)messageMediator.getBroker()).subcontractDebugFlag) { dprint(".createResponseHelper: " + opAndId(messageMediator) + ": " + reply); } messageMediator.setReplyHeader(reply); OutputObject replyOutputObject; // REVISIT = do not use null. // if (messageMediator.getConnection() == null) { replyOutputObject = sun.corba.OutputStreamFactory.newCDROutputObject(orb, messageMediator, messageMediator.getReplyHeader(), messageMediator.getStreamFormatVersion(), BufferManagerFactory.GROW); } else { replyOutputObject = messageMediator.getConnection().getAcceptor() .createOutputObject(messageMediator.getBroker(), messageMediator); } messageMediator.setOutputObject(replyOutputObject); messageMediator.getOutputObject().setMessageMediator(messageMediator); reply.write((OutputStream) messageMediator.getOutputObject()); if (reply.getIOR() != null) { reply.getIOR().write((OutputStream) messageMediator.getOutputObject()); } // REVISIT - not necessary? //messageMediator.this.replyIOR = reply.getIOR(); // NOTE: The mediator holds onto output object so return value // not really necessary. return messageMediator; } protected void runServantPostInvoke(CorbaMessageMediator messageMediator) { // Run ServantLocator::postinvoke. This may cause a SystemException // which will throw out of the constructor and return later // to construct a reply for that exception. The internal logic // of returnServant makes sure that postinvoke is only called once. // REVISIT: instead of instanceof, put method on all orbs. ORB orb = null; // This flag is to deal with BootstrapServer use of reply streams, // with ServerRequestDispatcher's use of reply streams, etc. if (messageMediator.executeReturnServantInResponseConstructor()) { // It is possible to get marshaling errors in the skeleton after // postinvoke has completed. We must set this to false so that // when the error exception reply is constructed we don't try // to incorrectly access poa current (which will be the wrong // one or an empty stack. messageMediator.setExecuteReturnServantInResponseConstructor(false); messageMediator.setExecuteRemoveThreadInfoInResponseConstructor(true); try { orb = (ORB)messageMediator.getBroker(); OAInvocationInfo info = orb.peekInvocationInfo() ; ObjectAdapter oa = info.oa(); try { oa.returnServant() ; } catch (Throwable thr) { wrapper.unexpectedException( thr ) ; if (thr instanceof Error) throw (Error)thr ; else if (thr instanceof RuntimeException) throw (RuntimeException)thr ; } finally { oa.exit(); } } catch (EmptyStackException ese) { throw wrapper.emptyStackRunServantPostInvoke( ese ) ; } } } protected void runInterceptors(CorbaMessageMediator messageMediator, ReplyMessage reply) { if( messageMediator.executePIInResponseConstructor() ) { // Invoke server request ending interception points (send_*): // Note: this may end up with a SystemException or an internal // Runtime ForwardRequest ((ORB)messageMediator.getBroker()).getPIHandler(). invokeServerPIEndingPoint( reply ); // Note this will be executed even if a ForwardRequest or // SystemException is thrown by a Portable Interceptors ending // point since we end up in this constructor again anyway. ((ORB)messageMediator.getBroker()).getPIHandler(). cleanupServerPIRequest(); // See createSystemExceptionResponse for why this is necesary. messageMediator.setExecutePIInResponseConstructor(false); } } protected void runRemoveThreadInfo(CorbaMessageMediator messageMediator) { // Once you get here then the final reply is available (i.e., // postinvoke and interceptors have completed. if (messageMediator.executeRemoveThreadInfoInResponseConstructor()) { messageMediator.setExecuteRemoveThreadInfoInResponseConstructor(false); ((ORB)messageMediator.getBroker()).popInvocationInfo() ; } } protected ServiceContexts getServiceContextsForReply( CorbaMessageMediator messageMediator, ServiceContexts contexts) { CorbaConnection c = (CorbaConnection) messageMediator.getConnection(); if (((ORB)messageMediator.getBroker()).subcontractDebugFlag) { dprint(".getServiceContextsForReply: " + opAndId(messageMediator) + ": " + c); } if (contexts == null) { contexts = new ServiceContexts(((ORB)messageMediator.getBroker())); } // NOTE : We only want to send the runtime context the first time if (c != null && !c.isPostInitialContexts()) { c.setPostInitialContexts(); SendingContextServiceContext scsc = new SendingContextServiceContext( ((ORB)messageMediator.getBroker()).getFVDCodeBaseIOR()) ; if (contexts.get( scsc.getId() ) != null) throw wrapper.duplicateSendingContextServiceContext() ; contexts.put( scsc ) ; if ( ((ORB)messageMediator.getBroker()).subcontractDebugFlag) dprint(".getServiceContextsForReply: " + opAndId(messageMediator) + ": added SendingContextServiceContext" ) ; } // send ORBVersion servicecontext as part of the Reply ORBVersionServiceContext ovsc = new ORBVersionServiceContext(ORBVersionFactory.getORBVersion()); if (contexts.get( ovsc.getId() ) != null) throw wrapper.duplicateOrbVersionServiceContext() ; contexts.put( ovsc ) ; if ( ((ORB)messageMediator.getBroker()).subcontractDebugFlag) dprint(".getServiceContextsForReply: " + opAndId(messageMediator) + ": added ORB version service context"); return contexts; } // REVISIT - this method should be migrated to orbutil.ORBUtility // since all locations that release ByteBuffers use // very similar logic and debug information. private void releaseByteBufferToPool() { if (dispatchByteBuffer != null) { orb.getByteBufferPool().releaseByteBuffer(dispatchByteBuffer); if (transportDebug()) { int bbId = System.identityHashCode(dispatchByteBuffer); StringBuffer sb = new StringBuffer(); sb.append(".handleInput: releasing ByteBuffer (" + bbId + ") to ByteBufferPool"); dprint(sb.toString()); } } } } // End of file.