/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Diagnostics; using System.Threading; namespace Apache.NMS.WCF { /// /// A generic base class for IAsyncResult implementations /// that wraps a ManualResetEvent. /// internal abstract class AsyncResult : IAsyncResult { private readonly AsyncCallback _callback; private readonly object _state; private readonly object _thisLock; private bool _completedSynchronously; private bool _endCalled; private Exception _exception; private bool _isCompleted; private ManualResetEvent _manualResetEvent; /// /// Initializes a new instance of the class. /// /// The callback. /// The state. protected AsyncResult(AsyncCallback callback, object state) { _callback = callback; _state = state; _thisLock = new object(); } /// /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// /// /// /// A user-defined object that qualifies or contains information about an asynchronous operation. /// public object AsyncState { get { return _state; } } /// /// Gets a that is used to wait for an asynchronous operation to complete. /// /// /// /// A that is used to wait for an asynchronous operation to complete. /// public WaitHandle AsyncWaitHandle { get { if(_manualResetEvent != null) { return _manualResetEvent; } lock(ThisLock) { if(_manualResetEvent == null) { _manualResetEvent = new ManualResetEvent(_isCompleted); } } return _manualResetEvent; } } /// /// Gets a value that indicates whether the asynchronous operation completed synchronously. /// /// /// true if the asynchronous operation completed synchronously; otherwise, false. /// public bool CompletedSynchronously { get { return _completedSynchronously; } } /// /// Gets a value that indicates whether the asynchronous operation has completed. /// /// /// true if the operation is complete; otherwise, false. /// public bool IsCompleted { get { return _isCompleted; } } /// /// Gets an object lock. /// /// The object lock. private object ThisLock { get { return _thisLock; } } // Call this version of complete when your asynchronous operation is complete. This will update the state // of the operation and notify the callback. /// /// Completes the specified completed synchronously. /// /// if set to [completed synchronously]. protected void Complete(bool completedSynchronously) { if(_isCompleted) { throw new InvalidOperationException("Cannot call Complete twice"); } _completedSynchronously = completedSynchronously; if(completedSynchronously) { // If we completedSynchronously, then there's no chance that the manualResetEvent was created so // we don't need to worry about a race Debug.Assert(_manualResetEvent == null, "No ManualResetEvent should be created for a synchronous AsyncResult."); _isCompleted = true; } else { lock(ThisLock) { _isCompleted = true; if(_manualResetEvent != null) { _manualResetEvent.Set(); } } } // If the callback throws, there is an error in the callback implementation if(_callback != null) { _callback(this); } } /// /// Call this version of complete if you raise an exception during processing. In addition to notifying /// the callback, it will capture the exception and store it to be thrown during AsyncResult.End. /// /// if set to [completed synchronously]. /// The exception. protected void Complete(bool completedSynchronously, Exception exception) { _exception = exception; Complete(completedSynchronously); } /// /// End should be called when the End function for the asynchronous operation is complete. It /// ensures the asynchronous operation is complete, and does some common validation. /// /// The type of the async result. /// The result. /// protected static TAsyncResult End(IAsyncResult result) where TAsyncResult : AsyncResult { if(result == null) { throw new ArgumentNullException("result"); } TAsyncResult asyncResult = result as TAsyncResult; if(asyncResult == null) { throw new ArgumentException("Invalid async messageBody.", "result"); } if(asyncResult._endCalled) { throw new InvalidOperationException("Async object already ended."); } asyncResult._endCalled = true; if(!asyncResult._isCompleted) { asyncResult.AsyncWaitHandle.WaitOne(); } if(asyncResult._manualResetEvent != null) { asyncResult._manualResetEvent.Close(); } if(asyncResult._exception != null) { throw asyncResult._exception; } return asyncResult; } } /// /// An AsyncResult that completes as soon as it is instantiated. /// internal class CompletedAsyncResult : AsyncResult { /// /// Initializes a new instance of the class. /// /// The callback. /// The state. public CompletedAsyncResult(AsyncCallback callback, object state) : base(callback, state) { Complete(true); } /// /// Ends the specified result. /// /// The result. public static void End(IAsyncResult result) { End(result); } } //A strongly typed AsyncResult internal abstract class TypedAsyncResult : AsyncResult { private T _data; /// /// Initializes a new instance of the class. /// /// The callback. /// The state. protected TypedAsyncResult(AsyncCallback callback, object state) : base(callback, state) { } /// /// Gets the data. /// /// The data. public T Data { get { return _data; } } /// /// Completes the specified data. /// /// The data. /// if set to [completed synchronously]. protected void Complete(T data, bool completedSynchronously) { _data = data; Complete(completedSynchronously); } /// /// Ends the specified result. /// /// The result. /// public static T End(IAsyncResult result) { TypedAsyncResult typedResult = End>(result); return typedResult.Data; } } //A strongly typed AsyncResult that completes as soon as it is instantiated. internal class TypedCompletedAsyncResult : TypedAsyncResult { /// /// Initializes a new instance of the class. /// /// The data. /// The callback. /// The state. public TypedCompletedAsyncResult(T data, AsyncCallback callback, object state) : base(callback, state) { Complete(data, true); } /// /// Finishes the async request. /// /// The result. /// public new static T End(IAsyncResult result) { TypedCompletedAsyncResult completedResult = result as TypedCompletedAsyncResult; if(completedResult == null) { throw new ArgumentException("Invalid async messageBody.", "messageBody"); } return TypedAsyncResult.End(completedResult); } } }