IceInternal.ConnectRequestHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ice-compat Show documentation
Show all versions of ice-compat 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 IceInternal;
import Ice.ConnectionI;
import java.util.concurrent.Callable;
public class ConnectRequestHandler
implements RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback
{
synchronized public RequestHandler
connect(Ice.ObjectPrxHelperBase proxy)
{
if(!initialized())
{
_proxies.add(proxy);
}
return _requestHandler;
}
@Override
public RequestHandler
update(RequestHandler previousHandler, RequestHandler newHandler)
{
return previousHandler == this ? newHandler : this;
}
@Override
public int
sendAsyncRequest(ProxyOutgoingAsyncBase out)
throws RetryException
{
synchronized(this)
{
if(!_initialized)
{
out.cancelable(this); // This will throw if the request is canceled
}
if(!initialized())
{
_requests.add(out);
return AsyncStatus.Queued;
}
}
return out.invokeRemote(_connection, _compress, _response);
}
@Override
public void
asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
{
synchronized(this)
{
if(_exception != null)
{
return; // The request has been notified of a failure already.
}
if(!initialized())
{
java.util.Iterator it = _requests.iterator();
while(it.hasNext())
{
OutgoingAsyncBase request = it.next();
if(request == outAsync)
{
it.remove();
if(outAsync.completed(ex))
{
outAsync.invokeCompletedAsync();
}
return;
}
}
assert(false); // The request has to be queued if it timed out and we're not initialized yet.
}
}
_connection.asyncRequestCanceled(outAsync, ex);
}
@Override
public Reference
getReference()
{
return _reference;
}
@Override
synchronized public ConnectionI
getConnection()
{
//
// First check for the connection, it's important otherwise the user could first get a connection
// and then the exception if he tries to obtain the proxy cached connection mutiple times (the
// exception can be set after the connection is set if the flush of pending requests fails).
//
if(_connection != null)
{
return _connection;
}
else if(_exception != null)
{
throw (Ice.LocalException)_exception.fillInStackTrace();
}
return null;
}
//
// Implementation of Reference.GetConnectionCallback
//
@Override
public void
setConnection(Ice.ConnectionI connection, boolean compress)
{
synchronized(this)
{
assert(!_flushing && _exception == null && _connection == null);
_connection = connection;
_compress = compress;
}
//
// If this proxy is for a non-local object, and we are using a router, then
// add this proxy to the router info object.
//
RouterInfo ri = _reference.getRouterInfo();
if(ri != null && !ri.addProxy(_proxy, this))
{
return; // The request handler will be initialized once addProxy returns.
}
//
// We can now send the queued requests.
//
flushRequests();
}
@Override
public void
setException(final Ice.LocalException ex)
{
synchronized(this)
{
assert(!_flushing && !_initialized && _exception == null);
_flushing = true; // Ensures request handler is removed before processing new requests.
_exception = ex;
}
//
// NOTE: remove the request handler *before* notifying the requests that the connection
// failed. It's important to ensure that future invocations will obtain a new connect
// request handler once invocations are notified.
//
try
{
_reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
}
catch(Ice.CommunicatorDestroyedException exc)
{
// Ignore
}
for(OutgoingAsyncBase outAsync : _requests)
{
if(outAsync.completed(_exception))
{
outAsync.invokeCompletedAsync();
}
}
_requests.clear();
synchronized(this)
{
_flushing = false;
_proxies.clear();
_proxy = null; // Break cyclic reference count.
notifyAll();
}
}
//
// Implementation of RouterInfo.AddProxyCallback
//
@Override
public void
addedProxy()
{
//
// The proxy was added to the router info, we're now ready to send the
// queued requests.
//
flushRequests();
}
public
ConnectRequestHandler(Reference ref, Ice.ObjectPrxHelperBase proxy)
{
_reference = ref;
_response = _reference.getMode() == Reference.ModeTwoway;
_proxy = (Ice.ObjectPrxHelperBase)proxy;
_initialized = false;
_flushing = false;
if(_reference.getInstance().queueRequests())
{
_requestHandler = new QueueRequestHandler(_reference.getInstance(), this);
}
else
{
_requestHandler = this;
}
}
private boolean
initialized()
{
// Must be called with the mutex locked.
if(_initialized)
{
assert(_connection != null);
return true;
}
else
{
//
// This is similar to a mutex lock in that the flag is
// only true for a short period of time.
//
boolean interrupted = false;
while(_flushing)
{
try
{
wait();
}
catch(InterruptedException ex)
{
interrupted = true;
}
}
//
// Restore the interrupted status.
//
if(interrupted)
{
Thread.currentThread().interrupt();
}
if(_exception != null)
{
if(_connection != null)
{
//
// Only throw if the connection didn't get established. If
// it died after being established, we allow the caller to
// retry the connection establishment by not throwing here
// (the connection will throw RetryException).
//
return true;
}
throw (Ice.LocalException)_exception.fillInStackTrace();
}
else
{
return _initialized;
}
}
}
private void
flushRequests()
{
if(_reference.getInstance().queueRequests())
{
_reference.getInstance().getQueueExecutor().executeNoThrow(new Callable()
{
@Override
public Void call() throws Exception
{
flushRequestsImpl();
return null;
}
});
}
else
{
flushRequestsImpl();
}
}
private void
flushRequestsImpl()
{
synchronized(this)
{
assert(!_flushing && _connection != null && !_initialized);
//
// We set the _flushing flag to true to prevent any additional queuing. Callers
// might block for a little while as the queued requests are being sent but this
// shouldn't be an issue as the request sends are non-blocking.
//
_flushing = true;
}
Ice.LocalException exception = null;
for(ProxyOutgoingAsyncBase outAsync : _requests)
{
try
{
if((outAsync.invokeRemote(_connection, _compress, _response) & AsyncStatus.InvokeSentCallback) > 0)
{
outAsync.invokeSentAsync();
}
}
catch(RetryException ex)
{
exception = ex.get();
// Remove the request handler before retrying.
_reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
outAsync.retryException(ex.get());
}
catch(Ice.LocalException ex)
{
exception = ex;
if(outAsync.completed(ex))
{
outAsync.invokeCompletedAsync();
}
}
}
_requests.clear();
//
// If we aren't caching the connection, don't bother creating a
// connection request handler. Otherwise, update the proxies
// request handler to use the more efficient connection request
// handler.
//
if(_reference.getCacheConnection() && exception == null)
{
RequestHandler previous = _requestHandler;
_requestHandler = new ConnectionRequestHandler(_reference, _connection, _compress);
if(_reference.getInstance().queueRequests())
{
_requestHandler = new QueueRequestHandler(_reference.getInstance(), _requestHandler);
}
for(Ice.ObjectPrxHelperBase proxy : _proxies)
{
proxy._updateRequestHandler(previous, _requestHandler);
}
}
synchronized(this)
{
assert(!_initialized);
_exception = exception;
_initialized = _exception == null;
_flushing = false;
//
// Only remove once all the requests are flushed to
// guarantee serialization.
//
_reference.getInstance().requestHandlerFactory().removeRequestHandler(_reference, this);
_proxies.clear();
_proxy = null; // Break cyclic reference count.
notifyAll();
}
}
private final Reference _reference;
private boolean _response;
private Ice.ObjectPrxHelperBase _proxy;
private java.util.Set _proxies = new java.util.HashSet();
private Ice.ConnectionI _connection;
private boolean _compress;
private Ice.LocalException _exception;
private boolean _initialized;
private boolean _flushing;
private java.util.List _requests = new java.util.LinkedList();
private RequestHandler _requestHandler;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy