// **********************************************************************
//
// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
package IceInternal;
public class OutgoingAsync extends Ice.AsyncResult implements OutgoingAsyncMessageCallback
{
public OutgoingAsync(Ice.ObjectPrx prx, String operation, CallbackBase callback)
{
super(((Ice.ObjectPrxHelperBase)prx).__reference().getInstance(), operation, callback);
_proxy = (Ice.ObjectPrxHelperBase)prx;
}
public void __prepare(String operation, Ice.OperationMode mode, java.util.Map<String, String> ctx,
boolean explicitCtx)
{
_delegate = null;
_cnt = 0;
_mode = mode;
_sentSynchronously = false;
if(explicitCtx && ctx == null)
{
ctx = _emptyContext;
}
//
// Can't call async via a batch proxy.
//
if(_proxy.ice_isBatchOneway() || _proxy.ice_isBatchDatagram())
{
throw new Ice.FeatureNotSupportedException("can't send batch requests with AMI");
}
_os.writeBlob(IceInternal.Protocol.requestHdr);
Reference ref = _proxy.__reference();
ref.getIdentity().__write(_os);
//
// For compatibility with the old FacetPath.
//
String facet = ref.getFacet();
if(facet == null || facet.length() == 0)
{
_os.writeStringSeq(null);
}
else
{
String[] facetPath = { facet };
_os.writeStringSeq(facetPath);
}
_os.writeString(operation);
_os.writeByte((byte)mode.ordinal());
if(ctx != null)
{
//
// Explicit context
//
Ice.ContextHelper.write(_os, ctx);
}
else
{
//
// Implicit context
//
Ice.ImplicitContextI implicitContext = ref.getInstance().getImplicitContext();
java.util.Map<String, String> prxContext = ref.getContext();
if(implicitContext == null)
{
Ice.ContextHelper.write(_os, prxContext);
}
else
{
implicitContext.write(prxContext, _os);
}
}
_os.startWriteEncaps();
}
public Ice.ObjectPrx getProxy()
{
return _proxy;
}
public boolean __sent(final Ice.ConnectionI connection)
{
synchronized(_monitor)
{
boolean alreadySent = (_state & Sent) != 0;
_state |= Sent;
if((_state & Done) == 0)
{
if(!_proxy.ice_isTwoway())
{
_state |= Done | OK;
}
else if(connection.timeout() > 0)
{
assert(_timerTaskConnection == null && _timerTask == null);
_timerTaskConnection = connection;
_timerTask = new TimerTask()
{
public void
runTimerTask()
{
__runTimerTask();
}
};
_instance.timer().schedule(_timerTask, connection.timeout());
}
}
_monitor.notifyAll();
return !alreadySent; // Don't call the sent call is already sent.
}
}
public void __sent()
{
__sentInternal();
}
public void __finished(Ice.LocalException exc, boolean sent)
{
synchronized(_monitor)
{
assert((_state & Done) == 0);
if(_timerTaskConnection != null)
{
_instance.timer().cancel(_timerTask);
_timerTaskConnection = null;
_timerTask = null;
}
}
//
// NOTE: at this point, synchronization isn't needed, no other threads should be
// calling on the callback.
//
try
{
int interval = handleException(exc, sent); // This will throw if the invocation can't be retried.
if(interval > 0)
{
_instance.retryQueue().add(this, interval);
}
else
{
__send(false);
}
}
catch(Ice.LocalException ex)
{
__exception(ex);
}
}
public final void __finished(LocalExceptionWrapper exc)
{
//
// NOTE: at this point, synchronization isn't needed, no other threads should be
// calling on the callback. The LocalExceptionWrapper exception is only called
// before the invocation is sent.
//
try
{
int interval = handleException(exc); // This will throw if the invocation can't be retried.
if(interval > 0)
{
_instance.retryQueue().add(this, interval);
}
else
{
__send(false);
}
}
catch(Ice.LocalException ex)
{
__exception(ex);
}
}
public final void __finished(BasicStream is)
{
assert(_proxy.ice_isTwoway()); // Can only be called for twoways.
byte replyStatus;
try
{
synchronized(_monitor)
{
assert(_exception == null && (_state & Done) == 0);
if(_timerTaskConnection != null)
{
_instance.timer().cancel(_timerTask);
_timerTaskConnection = null;
_timerTask = null;
}
_is.swap(is);
replyStatus = _is.readByte();
switch(replyStatus)
{
case ReplyStatus.replyOK:
case ReplyStatus.replyUserException:
{
break;
}
case ReplyStatus.replyObjectNotExist:
case ReplyStatus.replyFacetNotExist:
case ReplyStatus.replyOperationNotExist:
{
Ice.Identity id = new Ice.Identity();
id.__read(_is);
//
// For compatibility with the old FacetPath.
//
String[] facetPath = _is.readStringSeq();
String facet;
if(facetPath.length > 0)
{
if(facetPath.length > 1)
{
throw new Ice.MarshalException();
}
facet = facetPath[0];
}
else
{
facet = "";
}
String operation = _is.readString();
Ice.RequestFailedException ex = null;
switch(replyStatus)
{
case ReplyStatus.replyObjectNotExist:
{
ex = new Ice.ObjectNotExistException();
break;
}
case ReplyStatus.replyFacetNotExist:
{
ex = new Ice.FacetNotExistException();
break;
}
case ReplyStatus.replyOperationNotExist:
{
ex = new Ice.OperationNotExistException();
break;
}
default:
{
assert(false);
break;
}
}
ex.id = id;
ex.facet = facet;
ex.operation = operation;
throw ex;
}
case ReplyStatus.replyUnknownException:
case ReplyStatus.replyUnknownLocalException:
case ReplyStatus.replyUnknownUserException:
{
String unknown = _is.readString();
Ice.UnknownException ex = null;
switch(replyStatus)
{
case ReplyStatus.replyUnknownException:
{
ex = new Ice.UnknownException();
break;
}
case ReplyStatus.replyUnknownLocalException:
{
ex = new Ice.UnknownLocalException();
break;
}
case ReplyStatus.replyUnknownUserException:
{
ex = new Ice.UnknownUserException();
break;
}
default:
{
assert(false);
break;
}
}
ex.unknown = unknown;
throw ex;
}
default:
{
throw new Ice.UnknownReplyStatusException();
}
}
_state |= Done;
if(replyStatus == ReplyStatus.replyOK)
{
_state |= OK;
}
_monitor.notifyAll();
}
}
catch(Ice.LocalException ex)
{
__finished(ex, true);
return;
}
assert(replyStatus == ReplyStatus.replyOK || replyStatus == ReplyStatus.replyUserException);
__response();
}
public final boolean __send(boolean synchronous)
{
while(true)
{
int interval = 0;
try
{
_delegate = _proxy.__getDelegate(true);
int status = _delegate.__getRequestHandler().sendAsyncRequest(this);
if((status & AsyncStatus.Sent) > 0)
{
if(synchronous)
{
_sentSynchronously = true;
if((status & AsyncStatus.InvokeSentCallback) > 0)
{
__sent(); // Call from the user thread.
}
}
else
{
if((status & AsyncStatus.InvokeSentCallback) > 0)
{
__sentAsync(); // Call from a client thread pool thread.
}
}
}
break;
}
catch(LocalExceptionWrapper ex)
{
interval = handleException(ex);
}
catch(Ice.LocalException ex)
{
interval = handleException(ex, false);
}
if(interval > 0)
{
_instance.retryQueue().add(this, interval);
return false;
}
}
return _sentSynchronously;
}
private int handleException(Ice.LocalException exc, boolean sent)
{
Ice.IntHolder interval = new Ice.IntHolder(0);
try
{
//
// A CloseConnectionException indicates graceful server shutdown, and is therefore
// always repeatable without violating "at-most-once". That's because by sending a
// close connection message, the server guarantees that all outstanding requests
// can safely be repeated.
//
// An ObjectNotExistException can always be retried as well without violating
// "at-most-once" (see the implementation of the checkRetryAfterException method of
// the ProxyFactory class for the reasons why it can be useful).
//
if(!sent ||
exc instanceof Ice.CloseConnectionException ||
exc instanceof Ice.ObjectNotExistException)
{
throw exc;
}
//
// Throw the exception wrapped in a LocalExceptionWrapper, to indicate that the
// request cannot be resent without potentially violating the "at-most-once"
// principle.
//
throw new LocalExceptionWrapper(exc, false);
}
catch(LocalExceptionWrapper ex)
{
if(_mode == Ice.OperationMode.Nonmutating || _mode == Ice.OperationMode.Idempotent)
{
_cnt = _proxy.__handleExceptionWrapperRelaxed(_delegate, ex, interval, _cnt);
}
else
{
_proxy.__handleExceptionWrapper(_delegate, ex);
}
}
catch(Ice.LocalException ex)
{
_cnt = _proxy.__handleException(_delegate, ex, interval, _cnt);
}
return interval.value;
}
private int handleException(LocalExceptionWrapper ex)
{
Ice.IntHolder interval = new Ice.IntHolder(0);
if(_mode == Ice.OperationMode.Nonmutating || _mode == Ice.OperationMode.Idempotent)
{
_cnt = _proxy.__handleExceptionWrapperRelaxed(_delegate, ex, interval, _cnt);
}
else
{
_proxy.__handleExceptionWrapper(_delegate, ex);
}
return interval.value;
}
private final void
__runTimerTask()
{
Ice.ConnectionI connection;
synchronized(_monitor)
{
connection = _timerTaskConnection;
_timerTaskConnection = null;
_timerTask = null;
}
if(connection != null)
{
connection.exception(new Ice.TimeoutException());
}
}
protected Ice.ObjectPrxHelperBase _proxy;
private Ice.ConnectionI _timerTaskConnection;
private TimerTask _timerTask;
private Ice._ObjectDel _delegate;
private int _cnt;
private Ice.OperationMode _mode;
private static final java.util.Map<String, String> _emptyContext = new java.util.HashMap<String, String>();
}