// // Copyright (c) ZeroC, Inc. All rights reserved. // namespace Ice { /// /// /// Callback that requires the application to down-cast the proxy. /// /// public delegate void AsyncCallback(AsyncResult r); /// /// /// Callback for the successful completion of an operation /// that returns no data. /// /// public delegate void OnewayCallback(); /// /// /// Callback to inform when a call has been passed to the local /// transport. /// /// public delegate void SentCallback(bool sentSynchronously); /// /// /// Called when an invocation raises an exception. /// /// public delegate void ExceptionCallback(Ice.Exception ex); /// /// /// /// public interface AsyncResult : System.IAsyncResult { void cancel(); Communicator getCommunicator(); Connection getConnection(); ObjectPrx getProxy(); bool isCompleted_(); void waitForCompleted(); bool isSent(); void waitForSent(); void throwLocalException(); bool sentSynchronously(); string getOperation(); AsyncResult whenSent(AsyncCallback cb); AsyncResult whenSent(SentCallback cb); AsyncResult whenCompleted(ExceptionCallback excb); } public interface AsyncResult : AsyncResult { AsyncResult whenCompleted(T cb, ExceptionCallback excb); new AsyncResult whenCompleted(ExceptionCallback excb); new AsyncResult whenSent(SentCallback cb); } } namespace IceInternal { using System.Diagnostics; using System.Threading; abstract public class AsyncResultI : Ice.AsyncResult { public virtual void cancel() { Debug.Assert(outgoing_ != null); outgoing_.cancel(); } public Ice.Communicator getCommunicator() { return _communicator; } public virtual Ice.Connection getConnection() { return null; } public virtual Ice.ObjectPrx getProxy() { return null; } public bool isCompleted_() { lock(this) { return (state_ & StateDone) != 0; } } public void waitForCompleted() { lock(this) { while((state_ & StateDone) == 0) { Monitor.Wait(this); } } } public bool isSent() { lock(this) { return (state_ & StateSent) != 0; } } public void waitForSent() { lock(this) { while((state_ & StateSent) == 0 && exception_ == null) { Monitor.Wait(this); } } } public void throwLocalException() { lock(this) { if(exception_ != null) { throw exception_; } } } public bool sentSynchronously() { Debug.Assert(outgoing_ != null); return outgoing_.sentSynchronously(); // No lock needed } // // Implementation of System.IAsyncResult properties // public bool IsCompleted { get { return isCompleted_(); } } public bool CompletedSynchronously { get { Debug.Assert(outgoing_ != null); if(getProxy() != null && getProxy().ice_isTwoway()) { return false; } return outgoing_.sentSynchronously(); } } public object AsyncState { get { return _cookie; // No lock needed, cookie is immutable. } } public WaitHandle AsyncWaitHandle { get { lock(this) { if(waitHandle_ == null) { waitHandle_ = new EventWaitHandle(false, EventResetMode.ManualReset); } if((state_ & StateDone) != 0) { waitHandle_.Set(); } return waitHandle_; } } } public OutgoingAsyncBase OutgoingAsync { get { return outgoing_; } } public Ice.AsyncResult whenSent(Ice.AsyncCallback cb) { lock(this) { if(cb == null) { throw new System.ArgumentException("callback is null"); } if(sentCallback_ != null) { throw new System.ArgumentException("sent callback already set"); } sentCallback_ = cb; if((state_ & StateSent) == 0) { return this; } } if(outgoing_.sentSynchronously()) { try { sentCallback_(this); } catch(System.Exception ex) { warning(ex); } } else { instance_.clientThreadPool().dispatch(() => { try { sentCallback_(this); } catch(System.Exception ex) { warning(ex); } }, cachedConnection_); } return this; } public Ice.AsyncResult whenSent(Ice.SentCallback cb) { lock(this) { if(cb == null) { throw new System.ArgumentException("callback is null"); } if(sentCallback_ != null) { throw new System.ArgumentException("sent callback already set"); } sentCallback_ = (Ice.AsyncResult r) => { cb(r.sentSynchronously()); }; if((state_ & StateSent) == 0) { return this; } } if(outgoing_.sentSynchronously()) { try { cb(true); } catch(System.Exception ex) { warning(ex); } } else { instance_.clientThreadPool().dispatch(() => { try { cb(false); } catch(System.Exception ex) { warning(ex); } }, cachedConnection_); } return this; } public Ice.AsyncResult whenCompleted(Ice.ExceptionCallback cb) { if(cb == null) { throw new System.ArgumentException("callback is null"); } lock(this) { if(exceptionCallback_ != null) { throw new System.ArgumentException("callback already set"); } exceptionCallback_ = cb; } setCompletedCallback(getCompletedCallback()); return this; } public string getOperation() { return _operation; } public bool wait() { lock(this) { if((state_ & StateEndCalled) != 0) { throw new System.ArgumentException("end_ method called more than once"); } state_ |= StateEndCalled; while((state_ & StateDone) == 0) { Monitor.Wait(this); } if(exception_ != null) { throw exception_; } return (state_ & StateOK) != 0; } } protected AsyncResultI(Ice.Communicator communicator, Instance instance, string op, object cookie, Ice.AsyncCallback cb) { instance_ = instance; state_ = 0; _communicator = communicator; _operation = op; exception_ = null; _cookie = cookie; completedCallback_ = cb; } protected void setCompletedCallback(Ice.AsyncCallback cb) { lock(this) { if(cb == null) { throw new System.ArgumentException("callback is null"); } if(completedCallback_ != null) { throw new System.ArgumentException("callback already set"); } completedCallback_ = cb; if((state_ & StateDone) == 0) { return; } else if((getProxy() == null || !getProxy().ice_isTwoway()) && exception_ == null) { return; } } instance_.clientThreadPool().dispatch(() => { try { try { cb(this); } catch(System.AggregateException ex) { throw ex.InnerException; } } catch(System.Exception ex) { warning(ex); } }, cachedConnection_); } abstract protected Ice.AsyncCallback getCompletedCallback(); public static AsyncResultI check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation) { if(r != null && r.getProxy() != prx) { throw new System.ArgumentException("Proxy for call to end_" + operation + " does not match proxy that was used to call corresponding begin_" + operation + " method"); } return check(r, operation); } public static AsyncResultI check(Ice.AsyncResult r, string operation) { if(r == null) { throw new System.ArgumentException("AsyncResult == null"); } if(r.getOperation() != operation) { throw new System.ArgumentException("Incorrect operation for end_" + operation + " method: " + r.getOperation()); } if(!(r is AsyncResultI)) { throw new System.ArgumentException("Incorrect AsyncResult object for end_" + operation + " method"); } return (AsyncResultI)r; } protected void warning(System.Exception ex) { if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0) { instance_.initializationData().logger.warning("exception raised by AMI callback:\n" + ex); } } protected Instance instance_; protected Ice.Instrumentation.InvocationObserver observer_; protected Ice.Connection cachedConnection_; private readonly Ice.Communicator _communicator; private readonly string _operation; private readonly object _cookie; protected Ice.Exception exception_; protected EventWaitHandle waitHandle_; protected Ice.AsyncCallback completedCallback_; protected Ice.AsyncCallback sentCallback_; protected Ice.ExceptionCallback exceptionCallback_; protected const int StateOK = 0x1; protected const int StateDone = 0x2; protected const int StateSent = 0x4; protected const int StateEndCalled = 0x8; protected int state_; protected OutgoingAsyncBase outgoing_; } }