| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ |
| #define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ |
| |
| #include <deque> |
| |
| #include "base/synchronization/lock.h" |
| #include "ipc/ipc_channel_proxy.h" |
| |
| // Base class used to allow synchronous IPC messages to be sent and |
| // received in an asynchronous manner. To use this class add it as a filter to |
| // your IPC channel using ChannelProxy::AddFilter(). From then on, before |
| // sending a synchronous message, call SyncMessageReplyDispatcher::Push() with |
| // a callback and a key. This class will then handle the message response and |
| // will call the callback when it is received. |
| // |
| // This class is intended to be extended by classes implementing |
| // HandleMessageType with delegation for the messages they expect to receive in |
| // cases where you care about the return values of synchronous messages. |
| // |
| // Sample usage pattern: |
| // Define a class which inherits from SyncMessageCallContext which specifies |
| // the output_type tuple and has a Completed member function. |
| // class SampleContext |
| // : public SyncMessageReplyDispatcher::SyncMessageCallContext { |
| // public: |
| // typedef Tuple1<int> output_type; |
| // void Completed(int arg) {} |
| // }; |
| // |
| // // Add handling for desired message types. |
| // class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher { |
| // virtual bool HandleMessageType(const IPC::Message& msg, |
| // SyncMessageReplyDispatcher* context) { |
| // switch (context->message_type()) { |
| // case AutomationMsg_CreateExternalTab::ID: |
| // InvokeCallback<CreateExternalTabContext>(msg, context); |
| // break; |
| // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES] |
| // } |
| // } |
| // |
| // // Add the filter |
| // IPC::SyncChannel channel_; |
| // channel_.AddFilter(new SyncMessageReplyDispatcherImpl()); |
| // |
| // sync_->Push(msg, new SampleContext, this); |
| // channel_->ChannelProxy::Send(msg); |
| // |
| class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter { |
| public: |
| class SyncMessageCallContext { |
| public: |
| SyncMessageCallContext() |
| : id_(0), |
| message_type_(0), |
| key_(NULL) {} |
| |
| virtual ~SyncMessageCallContext() {} |
| |
| uint32 message_type() const { |
| return message_type_; |
| } |
| |
| private: |
| int id_; |
| uint32 message_type_; |
| void* key_; |
| |
| friend class SyncMessageReplyDispatcher; |
| }; |
| |
| SyncMessageReplyDispatcher() {} |
| void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context, |
| void* key); |
| void Cancel(void* key); |
| |
| protected: |
| typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue; |
| |
| SyncMessageCallContext* GetContext(const IPC::Message& msg); |
| |
| virtual bool OnMessageReceived(const IPC::Message& msg); |
| |
| // Child classes must implement a handler for the message types they are |
| // interested in handling responses for. If you don't care about the replies |
| // to any of the sync messages you are handling, then you don't have to |
| // implement this. |
| virtual bool HandleMessageType(const IPC::Message& msg, |
| SyncMessageCallContext* context); |
| |
| template <typename T> |
| void InvokeCallback(const IPC::Message& msg, |
| SyncMessageCallContext* call_context) { |
| if (!call_context || !call_context->key_) { |
| NOTREACHED() << "Invalid context parameter"; |
| return; |
| } |
| |
| T* context = static_cast<T*>(call_context); |
| T::output_type tmp; // Acts as "initializer" for output parameters. |
| IPC::ParamDeserializer<T::output_type> deserializer(tmp); |
| if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) { |
| DispatchToMethod(context, &T::Completed, deserializer.out_); |
| delete context; |
| } else { |
| // TODO(stoyan): How to handle errors? |
| } |
| } |
| |
| PendingSyncMessageQueue message_queue_; |
| base::Lock message_queue_lock_; |
| }; |
| |
| #endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_ |