1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 namespace Ice
6 {
7     ///
8     /// <summary>
9     /// Callback that requires the application to down-cast the proxy.
10     /// </summary>
11     ///
AsyncCallback(AsyncResult r)12     public delegate void AsyncCallback(AsyncResult r);
13 
14     ///
15     /// <summary>
16     /// Callback for the successful completion of an operation
17     /// that returns no data.
18     /// </summary>
19     ///
OnewayCallback()20     public delegate void OnewayCallback();
21 
22     ///
23     /// <summary>
24     /// Callback to inform when a call has been passed to the local
25     /// transport.
26     /// </summary>
27     ///
SentCallback(bool sentSynchronously)28     public delegate void SentCallback(bool sentSynchronously);
29 
30     ///
31     /// <summary>
32     /// Called when an invocation raises an exception.
33     /// </summary>
34     ///
ExceptionCallback(Ice.Exception ex)35     public delegate void ExceptionCallback(Ice.Exception ex);
36 
37     ///
38     /// <summary>
39     /// <!-- TODO -->
40     /// </summary>
41     public interface AsyncResult : System.IAsyncResult
42     {
cancel()43         void cancel();
44 
getCommunicator()45         Communicator getCommunicator();
46 
getConnection()47         Connection getConnection();
48 
getProxy()49         ObjectPrx getProxy();
50 
isCompleted_()51         bool isCompleted_();
52 
waitForCompleted()53         void waitForCompleted();
54 
isSent()55         bool isSent();
waitForSent()56         void waitForSent();
57 
throwLocalException()58         void throwLocalException();
59 
sentSynchronously()60         bool sentSynchronously();
61 
getOperation()62         string getOperation();
63 
whenSent(AsyncCallback cb)64         AsyncResult whenSent(AsyncCallback cb);
whenSent(SentCallback cb)65         AsyncResult whenSent(SentCallback cb);
whenCompleted(ExceptionCallback excb)66         AsyncResult whenCompleted(ExceptionCallback excb);
67     }
68 
69     public interface AsyncResult<T> : AsyncResult
70     {
whenCompleted(T cb, ExceptionCallback excb)71         AsyncResult<T> whenCompleted(T cb, ExceptionCallback excb);
72 
whenCompleted(ExceptionCallback excb)73         new AsyncResult<T> whenCompleted(ExceptionCallback excb);
whenSent(SentCallback cb)74         new AsyncResult<T> whenSent(SentCallback cb);
75     }
76 }
77 
78 namespace IceInternal
79 {
80     using System.Diagnostics;
81     using System.Threading;
82 
83     abstract public class AsyncResultI : Ice.AsyncResult
84     {
cancel()85         public virtual void cancel()
86         {
87             Debug.Assert(outgoing_ != null);
88             outgoing_.cancel();
89         }
90 
getCommunicator()91         public Ice.Communicator getCommunicator()
92         {
93             return _communicator;
94         }
95 
getConnection()96         public virtual Ice.Connection getConnection()
97         {
98             return null;
99         }
100 
getProxy()101         public virtual Ice.ObjectPrx getProxy()
102         {
103             return null;
104         }
105 
isCompleted_()106         public bool isCompleted_()
107         {
108             lock(this)
109             {
110                 return (state_ & StateDone) != 0;
111             }
112         }
113 
waitForCompleted()114         public void waitForCompleted()
115         {
116             lock(this)
117             {
118                 while((state_ & StateDone) == 0)
119                 {
120                     Monitor.Wait(this);
121                 }
122             }
123         }
124 
isSent()125         public bool isSent()
126         {
127             lock(this)
128             {
129                 return (state_ & StateSent) != 0;
130             }
131         }
132 
waitForSent()133         public void waitForSent()
134         {
135             lock(this)
136             {
137                 while((state_ & StateSent) == 0 && exception_ == null)
138                 {
139                     Monitor.Wait(this);
140                 }
141             }
142         }
143 
throwLocalException()144         public void throwLocalException()
145         {
146             lock(this)
147             {
148                 if(exception_ != null)
149                 {
150                     throw exception_;
151                 }
152             }
153         }
154 
sentSynchronously()155         public bool sentSynchronously()
156         {
157             Debug.Assert(outgoing_ != null);
158             return  outgoing_.sentSynchronously(); // No lock needed
159         }
160 
161         //
162         // Implementation of System.IAsyncResult properties
163         //
164         public bool IsCompleted
165         {
166             get
167             {
168                 return isCompleted_();
169             }
170         }
171 
172         public bool CompletedSynchronously
173         {
174             get
175             {
176                 Debug.Assert(outgoing_ != null);
177                 if(getProxy() != null && getProxy().ice_isTwoway())
178                 {
179                     return false;
180                 }
181                 return outgoing_.sentSynchronously();
182             }
183         }
184 
185         public object AsyncState
186         {
187             get
188             {
189                 return _cookie; // No lock needed, cookie is immutable.
190             }
191         }
192 
193         public WaitHandle AsyncWaitHandle
194         {
195             get
196             {
197                 lock(this)
198                 {
199                     if(waitHandle_ == null)
200                     {
201                         waitHandle_ = new EventWaitHandle(false, EventResetMode.ManualReset);
202                     }
203                     if((state_ & StateDone) != 0)
204                     {
205                         waitHandle_.Set();
206                     }
207                     return waitHandle_;
208                 }
209             }
210         }
211 
212         public OutgoingAsyncBase OutgoingAsync
213         {
214             get
215             {
216                 return outgoing_;
217             }
218         }
219 
whenSent(Ice.AsyncCallback cb)220         public Ice.AsyncResult whenSent(Ice.AsyncCallback cb)
221         {
222             lock(this)
223             {
224                 if(cb == null)
225                 {
226                     throw new System.ArgumentException("callback is null");
227                 }
228                 if(sentCallback_ != null)
229                 {
230                     throw new System.ArgumentException("sent callback already set");
231                 }
232                 sentCallback_ = cb;
233                 if((state_ & StateSent) == 0)
234                 {
235                     return this;
236                 }
237             }
238 
239             if(outgoing_.sentSynchronously())
240             {
241                 try
242                 {
243                     sentCallback_(this);
244                 }
245                 catch(System.Exception ex)
246                 {
247                     warning(ex);
248                 }
249             }
250             else
251             {
252                 instance_.clientThreadPool().dispatch(() =>
253                 {
254                     try
255                     {
256                         sentCallback_(this);
257                     }
258                     catch(System.Exception ex)
259                     {
260                         warning(ex);
261                     }
262                 }, cachedConnection_);
263             }
264             return this;
265         }
266 
whenSent(Ice.SentCallback cb)267         public Ice.AsyncResult whenSent(Ice.SentCallback cb)
268         {
269             lock(this)
270             {
271                 if(cb == null)
272                 {
273                     throw new System.ArgumentException("callback is null");
274                 }
275                 if(sentCallback_ != null)
276                 {
277                     throw new System.ArgumentException("sent callback already set");
278                 }
279                 sentCallback_ = (Ice.AsyncResult r) =>
280                     {
281                         cb(r.sentSynchronously());
282                     };
283                 if((state_ & StateSent) == 0)
284                 {
285                     return this;
286                 }
287             }
288 
289             if(outgoing_.sentSynchronously())
290             {
291                 try
292                 {
293                     cb(true);
294                 }
295                 catch(System.Exception ex)
296                 {
297                     warning(ex);
298                 }
299             }
300             else
301             {
302                 instance_.clientThreadPool().dispatch(() =>
303                 {
304                     try
305                     {
306                         cb(false);
307                     }
308                     catch(System.Exception ex)
309                     {
310                         warning(ex);
311                     }
312                 }, cachedConnection_);
313             }
314             return this;
315         }
316 
whenCompleted(Ice.ExceptionCallback cb)317         public Ice.AsyncResult whenCompleted(Ice.ExceptionCallback cb)
318         {
319             if(cb == null)
320             {
321                 throw new System.ArgumentException("callback is null");
322             }
323             lock(this)
324             {
325                 if(exceptionCallback_ != null)
326                 {
327                     throw new System.ArgumentException("callback already set");
328                 }
329                 exceptionCallback_ = cb;
330             }
331             setCompletedCallback(getCompletedCallback());
332             return this;
333         }
334 
getOperation()335         public string getOperation()
336         {
337             return _operation;
338         }
339 
wait()340         public bool wait()
341         {
342             lock(this)
343             {
344                 if((state_ & StateEndCalled) != 0)
345                 {
346                     throw new System.ArgumentException("end_ method called more than once");
347                 }
348                 state_ |= StateEndCalled;
349                 while((state_ & StateDone) == 0)
350                 {
351                     Monitor.Wait(this);
352                 }
353                 if(exception_ != null)
354                 {
355                     throw exception_;
356                 }
357                 return (state_ & StateOK) != 0;
358             }
359         }
360 
AsyncResultI(Ice.Communicator communicator, Instance instance, string op, object cookie, Ice.AsyncCallback cb)361         protected AsyncResultI(Ice.Communicator communicator,
362                                Instance instance,
363                                string op,
364                                object cookie,
365                                Ice.AsyncCallback cb)
366         {
367             instance_ = instance;
368             state_ = 0;
369 
370             _communicator = communicator;
371             _operation = op;
372             exception_ = null;
373             _cookie = cookie;
374             completedCallback_ = cb;
375         }
376 
setCompletedCallback(Ice.AsyncCallback cb)377         protected void setCompletedCallback(Ice.AsyncCallback cb)
378         {
379             lock(this)
380             {
381                 if(cb == null)
382                 {
383                     throw new System.ArgumentException("callback is null");
384                 }
385                 if(completedCallback_ != null)
386                 {
387                     throw new System.ArgumentException("callback already set");
388                 }
389                 completedCallback_ = cb;
390                 if((state_ & StateDone) == 0)
391                 {
392                     return;
393                 }
394                 else if((getProxy() == null || !getProxy().ice_isTwoway()) && exception_ == null)
395                 {
396                     return;
397                 }
398             }
399 
400             instance_.clientThreadPool().dispatch(() =>
401             {
402                 try
403                 {
404                     try
405                     {
406                         cb(this);
407                     }
408                     catch(System.AggregateException ex)
409                     {
410                         throw ex.InnerException;
411                     }
412                 }
413                 catch(System.Exception ex)
414                 {
415                     warning(ex);
416                 }
417             }, cachedConnection_);
418         }
419 
getCompletedCallback()420         abstract protected Ice.AsyncCallback getCompletedCallback();
421 
check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)422         public static AsyncResultI check(Ice.AsyncResult r, Ice.ObjectPrx prx, string operation)
423         {
424             if(r != null && r.getProxy() != prx)
425             {
426                 throw new System.ArgumentException("Proxy for call to end_" + operation +
427                                                    " does not match proxy that was used to call corresponding begin_" +
428                                                    operation + " method");
429             }
430             return check(r, operation);
431         }
432 
check(Ice.AsyncResult r, string operation)433         public static AsyncResultI check(Ice.AsyncResult r, string operation)
434         {
435             if(r == null)
436             {
437                 throw new System.ArgumentException("AsyncResult == null");
438             }
439             if(r.getOperation() != operation)
440             {
441                 throw new System.ArgumentException("Incorrect operation for end_" + operation + " method: " +
442                                                    r.getOperation());
443             }
444             if(!(r is AsyncResultI))
445             {
446                 throw new System.ArgumentException("Incorrect AsyncResult object for end_" + operation + " method");
447             }
448             return (AsyncResultI)r;
449         }
450 
warning(System.Exception ex)451         protected void warning(System.Exception ex)
452         {
453             if(instance_.initializationData().properties.getPropertyAsIntWithDefault("Ice.Warn.AMICallback", 1) > 0)
454             {
455                 instance_.initializationData().logger.warning("exception raised by AMI callback:\n" + ex);
456             }
457         }
458 
459         protected Instance instance_;
460         protected Ice.Instrumentation.InvocationObserver observer_;
461         protected Ice.Connection cachedConnection_;
462 
463         private readonly Ice.Communicator _communicator;
464         private readonly string _operation;
465         private readonly object _cookie;
466         protected Ice.Exception exception_;
467         protected EventWaitHandle waitHandle_;
468 
469         protected Ice.AsyncCallback completedCallback_;
470         protected Ice.AsyncCallback sentCallback_;
471         protected Ice.ExceptionCallback exceptionCallback_;
472 
473         protected const int StateOK = 0x1;
474         protected const int StateDone = 0x2;
475         protected const int StateSent = 0x4;
476         protected const int StateEndCalled = 0x8;
477         protected int state_;
478         protected OutgoingAsyncBase outgoing_;
479     }
480 }
481