• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Async.h

Go to the documentation of this file.
00001 /**
00002   Licensed to the Apache Software Foundation (ASF) under one
00003   or more contributor license agreements.  See the NOTICE file
00004   distributed with this work for additional information
00005   regarding copyright ownership.  The ASF licenses this file
00006   to you under the Apache License, Version 2.0 (the
00007   "License"); you may not use this file except in compliance
00008   with the License.  You may obtain a copy of the License at
00009 
00010       http://www.apache.org/licenses/LICENSE-2.0
00011 
00012   Unless required by applicable law or agreed to in writing, software
00013   distributed under the License is distributed on an "AS IS" BASIS,
00014   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015   See the License for the specific language governing permissions and
00016   limitations under the License.
00017  */
00018 
00019 /**
00020  * @file Async.h
00021  * @brief Provides constructs to perform async operations.
00022  */
00023 
00024 #pragma once
00025 #ifndef ATSCPPAPI_ASYNC_H_
00026 #define ATSCPPAPI_ASYNC_H_
00027 #include <list>
00028 #include <atscppapi/Mutex.h>
00029 #include <atscppapi/noncopyable.h>
00030 #include <atscppapi/shared_ptr.h>
00031 
00032 namespace atscppapi {
00033 
00034 /**
00035  * @private
00036  *
00037  * @brief This class represents the interface of a dispatch controller. A dispatch controller
00038  * is used to dispatch an event to a receiver. This interface exists so that the types in this
00039  * header file can be defined.
00040  */
00041 class AsyncDispatchControllerBase : noncopyable {
00042 public:
00043   /**
00044    * Dispatches an async event to a receiver.
00045    *
00046    * @return True if the receiver was still alive.
00047    */
00048   virtual bool dispatch() = 0;
00049 
00050   /** Renders dispatch unusable to communicate to receiver */
00051   virtual void disable() = 0;
00052 
00053   /** Returns true if receiver can be communicated with */
00054   virtual bool isEnabled() = 0;
00055 
00056   virtual ~AsyncDispatchControllerBase() { }
00057 };
00058 
00059 /**
00060  * @brief AsyncProvider is the interface that providers of async operations must implement. 
00061  * The system allows decoupling of the lifetime/scope of provider and receiver objects. The 
00062  * receiver object might have expired before the async operation is complete and the system
00063  * handles this case. Because of this decoupling, it is the responsibility of the provider
00064  * to manage it's expiration - self-destruct on completion is a good option.
00065  */
00066 class AsyncProvider {
00067 public:
00068   /**
00069    * This method is invoked when the async operation is requested. This call should be used
00070    * to just start the async operation and *not* block this thread. On completion, 
00071    * getDispatchController() can be used to invoke the receiver.
00072    */
00073   virtual void run() = 0;
00074 
00075   /** Base implementation just breaks communication channel with receiver. Implementations
00076    * should add business logic here. */
00077   virtual void cancel() {
00078     if (dispatch_controller_) {
00079       dispatch_controller_->disable();
00080     }
00081   }
00082 
00083   virtual ~AsyncProvider() { }
00084 
00085 protected:
00086   shared_ptr<AsyncDispatchControllerBase> getDispatchController() { return dispatch_controller_; }
00087 
00088 private:
00089   shared_ptr<AsyncDispatchControllerBase> dispatch_controller_;
00090   void doRun(shared_ptr<AsyncDispatchControllerBase> dispatch_controller) {
00091     dispatch_controller_ = dispatch_controller;
00092     run();
00093   }
00094   friend class Async;
00095 };
00096 
00097 /**
00098  * @private
00099  *
00100  * @brief Dispatch controller implementation. When invoking the receiver, it verifies that the
00101  * receiver is still alive, locks the mutex and then invokes handleAsyncComplete().
00102  */
00103 template<typename AsyncEventReceiverType, typename AsyncProviderType>
00104 class AsyncDispatchController : public AsyncDispatchControllerBase {
00105 public:
00106   bool dispatch() {
00107     bool ret = false;
00108     ScopedSharedMutexLock scopedLock(dispatch_mutex_);
00109     if (event_receiver_) {
00110       event_receiver_->handleAsyncComplete(static_cast<AsyncProviderType &>(*provider_));
00111       ret = true;
00112     }
00113     return ret;
00114   }
00115 
00116   void disable() {
00117     ScopedSharedMutexLock scopedLock(dispatch_mutex_);
00118     event_receiver_ = NULL;
00119   }
00120 
00121   bool isEnabled() {
00122     return (event_receiver_ != NULL);
00123   }
00124 
00125   /**
00126    * Constructor
00127    *
00128    * @param event_receiver The async complete event will be dispatched to this receiver.
00129    * @param provider Async operation provider that is passed to the receiver on dispatch.
00130    * @param mutex Mutex of the receiver that is locked during the dispatch
00131    */
00132   AsyncDispatchController(AsyncEventReceiverType *event_receiver, AsyncProviderType *provider, shared_ptr<Mutex> mutex) :
00133     event_receiver_(event_receiver), dispatch_mutex_(mutex), provider_(provider) {
00134   }
00135 
00136   virtual ~AsyncDispatchController() { }
00137 public:
00138   AsyncEventReceiverType *event_receiver_;
00139   shared_ptr<Mutex> dispatch_mutex_;
00140 private:
00141   AsyncProviderType *provider_;
00142 };
00143 
00144 /**
00145  * @private
00146  * 
00147  * @brief A promise is used to let the dispatch controller know if the receiver is still
00148  * alive to receive the async complete dispatch. When the receiver dies, this promise is
00149  * broken and it automatically updates the dispatch controller.
00150  */
00151 template<typename AsyncEventReceiverType, typename AsyncProviderType>
00152 class AsyncReceiverPromise : noncopyable {
00153 public:
00154   AsyncReceiverPromise(shared_ptr<AsyncDispatchController<AsyncEventReceiverType, AsyncProviderType> > dispatch_controller) :
00155     dispatch_controller_(dispatch_controller) { }
00156 
00157   ~AsyncReceiverPromise() {
00158     ScopedSharedMutexLock scopedLock(dispatch_controller_->dispatch_mutex_);
00159     dispatch_controller_->event_receiver_ = NULL;
00160   }
00161 protected:
00162   shared_ptr<AsyncDispatchController<AsyncEventReceiverType, AsyncProviderType> > dispatch_controller_;
00163 };
00164 
00165 /**
00166  * @brief AsyncReceiver is the interface that receivers of async operations must implement. It is
00167  * templated on the type of the async operation provider.
00168  */
00169 template<typename AsyncProviderType>
00170 class AsyncReceiver : noncopyable {
00171 public:
00172   /**
00173    * This method is invoked when the async operation is completed. The
00174    * mutex provided during the creation of the async operation will be
00175    * automatically locked during the invocation of this method.
00176    *
00177    * @param provider A reference to the provider which completed the async operation.
00178    */
00179   virtual void handleAsyncComplete(AsyncProviderType &provider) = 0;
00180   virtual ~AsyncReceiver() { }
00181 protected:
00182   AsyncReceiver() { }
00183   friend class Async;
00184 private:
00185   mutable std::list<shared_ptr<AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType> > > receiver_promises_;
00186 };
00187 
00188 /**
00189  * @brief This class provides a method to create an async operation.
00190  */
00191 class Async : noncopyable {
00192 public:
00193   /**
00194    * This method sets up the dispatch controller to link the async operation provider and 
00195    * receiver and then initiates the operation by invoking the provider. 
00196    *
00197    * @param event_receiver The receiver of the async complete dispatch.
00198    * @param provider The provider of the async operation.
00199    * @param mutex The mutex that is locked during the dispatch of the async event complete.
00200    *              One will be created if nothing is passed in. Transaction plugins should use 
00201    *              TransactionPlugin::getMutex() here and global plugins can pass an appropriate
00202    *              or NULL mutex.
00203    */
00204   template<typename AsyncProviderType>
00205   static void execute(AsyncReceiver<AsyncProviderType> *event_receiver, AsyncProviderType *provider, shared_ptr<Mutex> mutex) {
00206     if (!mutex.get()) {
00207       mutex.reset(new Mutex(Mutex::TYPE_RECURSIVE));
00208     }
00209     shared_ptr<AsyncDispatchController<AsyncReceiver<AsyncProviderType>, AsyncProviderType > > dispatcher(
00210       new AsyncDispatchController<AsyncReceiver<AsyncProviderType>, AsyncProviderType >(event_receiver, provider, mutex));
00211     shared_ptr<AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType > > receiver_promise(
00212       new AsyncReceiverPromise<AsyncReceiver<AsyncProviderType>, AsyncProviderType >(dispatcher));
00213     event_receiver->receiver_promises_.push_back(receiver_promise); // now if the event receiver dies, we're safe.
00214     provider->doRun(dispatcher);
00215   }
00216 };
00217 
00218 }
00219 
00220 
00221 #endif /* ATSCPPAPI_ASYNC_H_ */

Generated by  doxygen 1.7.1