com.zeroc.IceInternal.CollocatedRequestHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice Show documentation
Show all versions of ice Show documentation
Ice is a comprehensive RPC framework that helps you build distributed applications with minimal effort using familiar object-oriented idioms
//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
package com.zeroc.IceInternal;
public class CollocatedRequestHandler implements RequestHandler, ResponseHandler
{
private class InvokeAllAsync extends DispatchWorkItem
{
private InvokeAllAsync(OutgoingAsyncBase outAsync, com.zeroc.Ice.OutputStream os, int requestId,
int batchRequestNum)
{
_outAsync = outAsync;
_os = os;
_requestId = requestId;
_batchRequestNum = batchRequestNum;
}
@Override
public void run()
{
if(sentAsync(_outAsync))
{
invokeAll(_os, _requestId, _batchRequestNum);
}
}
private final OutgoingAsyncBase _outAsync;
private com.zeroc.Ice.OutputStream _os;
private final int _requestId;
private final int _batchRequestNum;
}
public
CollocatedRequestHandler(Reference ref, com.zeroc.Ice.ObjectAdapter adapter)
{
_reference = ref;
_dispatcher = ref.getInstance().initializationData().dispatcher != null;
_adapter = (com.zeroc.Ice.ObjectAdapterI)adapter;
_response = _reference.getMode() == Reference.ModeTwoway;
_logger = _reference.getInstance().initializationData().logger; // Cached for better performance.
_traceLevels = _reference.getInstance().traceLevels(); // Cached for better performance.
_requestId = 0;
}
@Override
public RequestHandler
update(RequestHandler previousHandler, RequestHandler newHandler)
{
return previousHandler == this ? newHandler : this;
}
@Override
public int
sendAsyncRequest(ProxyOutgoingAsyncBase outAsync)
{
return outAsync.invokeCollocated(this);
}
@Override
synchronized public void
asyncRequestCanceled(OutgoingAsyncBase outAsync, com.zeroc.Ice.LocalException ex)
{
Integer requestId = _sendAsyncRequests.remove(outAsync);
if(requestId != null)
{
if(requestId > 0)
{
_asyncRequests.remove(requestId);
}
if(outAsync.completed(ex))
{
outAsync.invokeCompletedAsync();
}
_adapter.decDirectCount(); // invokeAll won't be called, decrease the direct count.
return;
}
if(outAsync instanceof OutgoingAsync)
{
for(java.util.Map.Entry e : _asyncRequests.entrySet())
{
if(e.getValue() == outAsync)
{
_asyncRequests.remove(e.getKey());
if(outAsync.completed(ex))
{
outAsync.invokeCompletedAsync();
}
return;
}
}
}
}
@Override
public void
sendResponse(int requestId, final com.zeroc.Ice.OutputStream os, byte status, boolean amd)
{
OutgoingAsyncBase outAsync = null;
synchronized(this)
{
assert(_response);
if(_traceLevels.protocol >= 1)
{
fillInValue(os, 10, os.size());
}
// Adopt the OutputStream's buffer.
com.zeroc.Ice.InputStream is =
new com.zeroc.Ice.InputStream(os.instance(), os.getEncoding(), os.getBuffer(), true);
is.pos(Protocol.replyHdr.length + 4);
if(_traceLevels.protocol >= 1)
{
TraceUtil.traceRecv(is, _logger, _traceLevels);
}
outAsync = _asyncRequests.remove(requestId);
if(outAsync != null && !outAsync.completed(is))
{
outAsync = null;
}
}
if(outAsync != null)
{
//
// If called from an AMD dispatch, invoke asynchronously
// the completion callback since this might be called from
// the user code.
//
if(amd)
{
outAsync.invokeCompletedAsync();
}
else
{
outAsync.invokeCompleted();
}
}
_adapter.decDirectCount();
}
@Override
public void
sendNoResponse()
{
_adapter.decDirectCount();
}
@Override
public boolean
systemException(int requestId, com.zeroc.Ice.SystemException ex, boolean amd)
{
handleException(requestId, ex, amd);
_adapter.decDirectCount();
return true;
}
@Override
public void
invokeException(int requestId, com.zeroc.Ice.LocalException ex, int batchRequestNum, boolean amd)
{
handleException(requestId, ex, amd);
_adapter.decDirectCount();
}
@Override
public Reference
getReference()
{
return _reference;
}
@Override
public com.zeroc.Ice.ConnectionI
getConnection()
{
return null;
}
int invokeAsyncRequest(OutgoingAsyncBase outAsync, int batchRequestNum, boolean sync)
{
//
// Increase the direct count to prevent the thread pool from being destroyed before
// invokeAll is called. This will also throw if the object adapter has been deactivated.
//
_adapter.incDirectCount();
int requestId = 0;
try
{
synchronized(this)
{
outAsync.cancelable(this); // This will throw if the request is canceled
if(_response)
{
requestId = ++_requestId;
_asyncRequests.put(requestId, outAsync);
}
_sendAsyncRequests.put(outAsync, requestId);
}
}
catch(Exception ex)
{
_adapter.decDirectCount();
throw ex;
}
outAsync.attachCollocatedObserver(_adapter, requestId);
if(!sync || !_response || _reference.getInstance().queueRequests() || _reference.getInvocationTimeout() > 0)
{
_adapter.getThreadPool().dispatch(new InvokeAllAsync(outAsync,
outAsync.getOs(),
requestId,
batchRequestNum));
}
else if(_dispatcher)
{
_adapter.getThreadPool().dispatchFromThisThread(new InvokeAllAsync(outAsync,
outAsync.getOs(),
requestId,
batchRequestNum));
}
else // Optimization: directly call invokeAll if there's no dispatcher.
{
if(sentAsync(outAsync))
{
invokeAll(outAsync.getOs(), requestId, batchRequestNum);
}
}
return AsyncStatus.Queued;
}
private boolean
sentAsync(final OutgoingAsyncBase outAsync)
{
synchronized(this)
{
if(_sendAsyncRequests.remove(outAsync) == null)
{
return false; // The request timed-out.
}
//
// This must be called within the synchronization to
// ensure completed(ex) can't be called concurrently if
// the request is canceled.
//
if(!outAsync.sent())
{
return true;
}
}
outAsync.invokeSent();
return true;
}
private void
invokeAll(com.zeroc.Ice.OutputStream os, int requestId, int batchRequestNum)
{
if(_traceLevels.protocol >= 1)
{
fillInValue(os, 10, os.size());
if(requestId > 0)
{
fillInValue(os, Protocol.headerSize, requestId);
}
else if(batchRequestNum > 0)
{
fillInValue(os, Protocol.headerSize, batchRequestNum);
}
TraceUtil.traceSend(os, _logger, _traceLevels);
}
com.zeroc.Ice.InputStream is =
new com.zeroc.Ice.InputStream(os.instance(), os.getEncoding(), os.getBuffer(), false);
if(batchRequestNum > 0)
{
is.pos(Protocol.requestBatchHdr.length);
}
else
{
is.pos(Protocol.requestHdr.length);
}
int invokeNum = batchRequestNum > 0 ? batchRequestNum : 1;
ServantManager servantManager = _adapter.getServantManager();
try
{
while(invokeNum > 0)
{
//
// Increase the direct count for the dispatch. We increase it again here for
// each dispatch. It's important for the direct count to be > 0 until the last
// collocated request response is sent to make sure the thread pool isn't
// destroyed before.
//
try
{
_adapter.incDirectCount();
}
catch(com.zeroc.Ice.ObjectAdapterDeactivatedException ex)
{
handleException(requestId, ex, false);
break;
}
Incoming in = new Incoming(_reference.getInstance(), this, null, _adapter, _response, (byte)0,
requestId);
in.invoke(servantManager, is);
--invokeNum;
}
}
catch(com.zeroc.Ice.LocalException ex)
{
invokeException(requestId, ex, invokeNum, false); // Fatal invocation exception
}
catch(ServantError ex)
{
//
// ServantError is thrown when an Error has been raised by servant (or servant locator)
// code. We've already attempted to complete the invocation and send a response.
//
Throwable t = ex.getCause();
//
// Suppress AssertionError and OutOfMemoryError, rethrow everything else.
//
if(!(t instanceof java.lang.AssertionError ||
t instanceof java.lang.OutOfMemoryError ||
t instanceof java.lang.StackOverflowError))
{
throw (java.lang.Error)t;
}
}
catch(java.lang.Error ex)
{
//
// An Error was raised outside of servant code (i.e., by Ice code).
// Attempt to log the error and clean up. This may still fail
// depending on the severity of the error.
//
// Note that this does NOT send a response to the client.
//
com.zeroc.Ice.UnknownException uex = new com.zeroc.Ice.UnknownException(ex);
java.io.StringWriter sw = new java.io.StringWriter();
java.io.PrintWriter pw = new java.io.PrintWriter(sw);
ex.printStackTrace(pw);
pw.flush();
uex.unknown = sw.toString();
_logger.error(uex.unknown);
invokeException(requestId, uex, invokeNum, false);
//
// Suppress AssertionError and OutOfMemoryError, rethrow everything else.
//
if(!(ex instanceof java.lang.AssertionError ||
ex instanceof java.lang.OutOfMemoryError ||
ex instanceof java.lang.StackOverflowError))
{
throw ex;
}
}
finally
{
_adapter.decDirectCount();
}
}
private void
handleException(int requestId, com.zeroc.Ice.Exception ex, boolean amd)
{
if(requestId == 0)
{
return; // Ignore exception for oneway messages.
}
OutgoingAsyncBase outAsync = null;
synchronized(this)
{
outAsync = _asyncRequests.remove(requestId);
if(outAsync != null && !outAsync.completed(ex))
{
outAsync = null;
}
}
if(outAsync != null)
{
//
// If called from an AMD dispatch, invoke asynchronously
// the completion callback since this might be called from
// the user code.
//
if(amd)
{
outAsync.invokeCompletedAsync();
}
else
{
outAsync.invokeCompleted();
}
}
}
private void
fillInValue(com.zeroc.Ice.OutputStream os, int pos, int value)
{
os.rewriteInt(value, pos);
}
private final Reference _reference;
private final boolean _dispatcher;
private final boolean _response;
private final com.zeroc.Ice.ObjectAdapterI _adapter;
private final com.zeroc.Ice.Logger _logger;
private final TraceLevels _traceLevels;
private int _requestId;
// A map of outstanding requests that can be canceled. A request
// can be canceled if it has an invocation timeout, or we support
// interrupts.
private java.util.Map _sendAsyncRequests = new java.util.HashMap<>();
private java.util.Map _asyncRequests = new java.util.HashMap<>();
}