Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 // DevTools RPC subsystem is a simple string serialization-based rpc
     32 // implementation. The client is responsible for defining the Rpc-enabled
     33 // interface in terms of its macros:
     34 //
     35 // #define MYAPI_STRUCT(METHOD0, METHOD1, METHOD2, METHOD3)
     36 //   METHOD0(Method1)
     37 //   METHOD1(Method3, int)
     38 // (snippet above should be multiline macro, add trailing backslashes)
     39 //
     40 // DEFINE_RPC_CLASS(MyApi, MYAPI_STRUCT)
     41 //
     42 // The snippet above will generate three classes: MyApi, MyApiStub and
     43 // MyApiDispatch.
     44 //
     45 // 1. For each method defined in the marco MyApi will have a
     46 // pure virtual function generated, so that MyApi would look like:
     47 //
     48 // class MyApi {
     49 // private:
     50 //     MyApi() { }
     51 //     ~MyApi() { }
     52 //     virtual void method1() = 0;
     53 //     virtual void method2(
     54 //         int param1,
     55 //         const String& param2,
     56 //         const Value& param3) = 0;
     57 //     virtual void method3(int param1) = 0;
     58 // };
     59 //
     60 // 2. MyApiStub will implement MyApi interface and would serialize all calls
     61 // into the string-based calls of the underlying transport:
     62 //
     63 // DevToolsRPC::Delegate* transport;
     64 // myApi = new MyApiStub(transport);
     65 // myApi->method1();
     66 // myApi->method3(2);
     67 //
     68 // 3. MyApiDelegate is capable of dispatching the calls and convert them to the
     69 // calls to the underlying MyApi methods:
     70 //
     71 // MyApi* realObject;
     72 // MyApiDispatch::dispatch(realObject, rawStringCallGeneratedByStub);
     73 //
     74 // will make corresponding calls to the real object.
     75 
     76 #ifndef DevToolsRPC_h
     77 #define DevToolsRPC_h
     78 
     79 #include "PlatformString.h"
     80 #include "Vector.h"
     81 #include "WebDevToolsMessageData.h"
     82 
     83 #include <wtf/Noncopyable.h>
     84 
     85 namespace WebCore {
     86 class String;
     87 }
     88 
     89 using WebCore::String;
     90 using WTF::Vector;
     91 
     92 namespace WebKit {
     93 
     94 ///////////////////////////////////////////////////////
     95 // RPC dispatch macro
     96 
     97 template<typename T>
     98 struct RpcTypeTrait {
     99     typedef T ApiType;
    100 };
    101 
    102 template<>
    103 struct RpcTypeTrait<bool> {
    104     typedef bool ApiType;
    105     static bool parse(const WebCore::String& t)
    106     {
    107         return t == "true";
    108     }
    109     static WebCore::String toString(bool b)
    110     {
    111         return b ? "true" : "false";
    112     }
    113 };
    114 
    115 template<>
    116 struct RpcTypeTrait<int> {
    117     typedef int ApiType;
    118     static int parse(const WebCore::String& t)
    119     {
    120         bool success;
    121         int i = t.toIntStrict(&success);
    122         ASSERT(success);
    123         return i;
    124     }
    125     static WebCore::String toString(int i)
    126     {
    127         return WebCore::String::number(i);
    128     }
    129 };
    130 
    131 template<>
    132 struct RpcTypeTrait<String> {
    133     typedef const String& ApiType;
    134     static String parse(const WebCore::String& t)
    135     {
    136         return t;
    137     }
    138     static WebCore::String toString(const String& t)
    139     {
    140         return t;
    141     }
    142 };
    143 
    144 ///////////////////////////////////////////////////////
    145 // RPC Api method declarations
    146 
    147 #define TOOLS_RPC_API_METHOD0(Method) \
    148     virtual void Method() = 0;
    149 
    150 #define TOOLS_RPC_API_METHOD1(Method, T1) \
    151     virtual void Method(RpcTypeTrait<T1>::ApiType t1) = 0;
    152 
    153 #define TOOLS_RPC_API_METHOD2(Method, T1, T2) \
    154     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    155                         RpcTypeTrait<T2>::ApiType t2) = 0;
    156 
    157 #define TOOLS_RPC_API_METHOD3(Method, T1, T2, T3) \
    158     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    159                         RpcTypeTrait<T2>::ApiType t2, \
    160                         RpcTypeTrait<T3>::ApiType t3) = 0;
    161 
    162 #define TOOLS_RPC_API_METHOD4(Method, T1, T2, T3, T4) \
    163     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    164                         RpcTypeTrait<T2>::ApiType t2, \
    165                         RpcTypeTrait<T3>::ApiType t3, \
    166                         RpcTypeTrait<T4>::ApiType t4) = 0;
    167 
    168 #define TOOLS_RPC_API_METHOD5(Method, T1, T2, T3, T4, T5) \
    169     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    170                         RpcTypeTrait<T2>::ApiType t2, \
    171                         RpcTypeTrait<T3>::ApiType t3, \
    172                         RpcTypeTrait<T4>::ApiType t4, \
    173                         RpcTypeTrait<T5>::ApiType t5) = 0;
    174 
    175 ///////////////////////////////////////////////////////
    176 // RPC stub method implementations
    177 
    178 #define TOOLS_RPC_STUB_METHOD0(Method) \
    179     virtual void Method() { \
    180         Vector<String> args; \
    181         this->sendRpcMessage(m_className, #Method, args); \
    182     }
    183 
    184 #define TOOLS_RPC_STUB_METHOD1(Method, T1) \
    185     virtual void Method(RpcTypeTrait<T1>::ApiType t1) { \
    186         Vector<String> args(1); \
    187         args[0] = RpcTypeTrait<T1>::toString(t1); \
    188         this->sendRpcMessage(m_className, #Method, args); \
    189     }
    190 
    191 #define TOOLS_RPC_STUB_METHOD2(Method, T1, T2) \
    192     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    193                         RpcTypeTrait<T2>::ApiType t2) { \
    194         Vector<String> args(2); \
    195         args[0] = RpcTypeTrait<T1>::toString(t1); \
    196         args[1] = RpcTypeTrait<T2>::toString(t2); \
    197         this->sendRpcMessage(m_className, #Method, args); \
    198     }
    199 
    200 #define TOOLS_RPC_STUB_METHOD3(Method, T1, T2, T3) \
    201     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    202                         RpcTypeTrait<T2>::ApiType t2, \
    203                         RpcTypeTrait<T3>::ApiType t3) { \
    204         Vector<String> args(3); \
    205         args[0] = RpcTypeTrait<T1>::toString(t1); \
    206         args[1] = RpcTypeTrait<T2>::toString(t2); \
    207         args[2] = RpcTypeTrait<T3>::toString(t3); \
    208         this->sendRpcMessage(m_className, #Method, args); \
    209     }
    210 
    211 #define TOOLS_RPC_STUB_METHOD4(Method, T1, T2, T3, T4) \
    212     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    213                         RpcTypeTrait<T2>::ApiType t2, \
    214                         RpcTypeTrait<T3>::ApiType t3, \
    215                         RpcTypeTrait<T4>::ApiType t4) { \
    216         Vector<String> args(4); \
    217         args[0] = RpcTypeTrait<T1>::toString(t1); \
    218         args[1] = RpcTypeTrait<T2>::toString(t2); \
    219         args[2] = RpcTypeTrait<T3>::toString(t3); \
    220         args[3] = RpcTypeTrait<T4>::toString(t4); \
    221         this->sendRpcMessage(m_className, #Method, args); \
    222     }
    223 
    224 #define TOOLS_RPC_STUB_METHOD5(Method, T1, T2, T3, T4, T5) \
    225     virtual void Method(RpcTypeTrait<T1>::ApiType t1, \
    226                         RpcTypeTrait<T2>::ApiType t2, \
    227                         RpcTypeTrait<T3>::ApiType t3, \
    228                         RpcTypeTrait<T4>::ApiType t4, \
    229                         RpcTypeTrait<T5>::ApiType t5) { \
    230         Vector<String> args(5); \
    231         args[0] = RpcTypeTrait<T1>::toString(t1); \
    232         args[1] = RpcTypeTrait<T2>::toString(t2); \
    233         args[2] = RpcTypeTrait<T3>::toString(t3); \
    234         args[3] = RpcTypeTrait<T4>::toString(t4); \
    235         args[4] = RpcTypeTrait<T5>::toString(t5); \
    236         this->sendRpcMessage(m_className, #Method, args); \
    237     }
    238 
    239 ///////////////////////////////////////////////////////
    240 // RPC dispatch method implementations
    241 
    242 #define TOOLS_RPC_DISPATCH0(Method) \
    243 if (methodName == #Method) { \
    244     delegate->Method(); \
    245     return true; \
    246 }
    247 
    248 #define TOOLS_RPC_DISPATCH1(Method, T1) \
    249 if (methodName == #Method) { \
    250     delegate->Method(RpcTypeTrait<T1>::parse(args[0])); \
    251     return true; \
    252 }
    253 
    254 #define TOOLS_RPC_DISPATCH2(Method, T1, T2) \
    255 if (methodName == #Method) { \
    256     delegate->Method( \
    257         RpcTypeTrait<T1>::parse(args[0]), \
    258         RpcTypeTrait<T2>::parse(args[1]) \
    259     ); \
    260     return true; \
    261 }
    262 
    263 #define TOOLS_RPC_DISPATCH3(Method, T1, T2, T3) \
    264 if (methodName == #Method) { \
    265     delegate->Method( \
    266         RpcTypeTrait<T1>::parse(args[0]), \
    267         RpcTypeTrait<T2>::parse(args[1]), \
    268         RpcTypeTrait<T3>::parse(args[2]) \
    269     ); \
    270     return true; \
    271 }
    272 
    273 #define TOOLS_RPC_DISPATCH4(Method, T1, T2, T3, T4) \
    274 if (methodName == #Method) { \
    275     delegate->Method( \
    276         RpcTypeTrait<T1>::parse(args[0]), \
    277         RpcTypeTrait<T2>::parse(args[1]), \
    278         RpcTypeTrait<T3>::parse(args[2]), \
    279         RpcTypeTrait<T4>::parse(args[3]) \
    280     ); \
    281     return true; \
    282 }
    283 
    284 #define TOOLS_RPC_DISPATCH5(Method, T1, T2, T3, T4, T5) \
    285 if (methodName == #Method) { \
    286     delegate->Method( \
    287         RpcTypeTrait<T1>::parse(args[0]), \
    288         RpcTypeTrait<T2>::parse(args[1]), \
    289         RpcTypeTrait<T3>::parse(args[2]), \
    290         RpcTypeTrait<T4>::parse(args[3]), \
    291         RpcTypeTrait<T5>::parse(args[4]) \
    292     ); \
    293     return true; \
    294 }
    295 
    296 #define TOOLS_END_RPC_DISPATCH() \
    297 }
    298 
    299 // This macro defines three classes: Class with the Api, ClassStub that is
    300 // serializing method calls and ClassDispatch that is capable of dispatching
    301 // the serialized message into its delegate.
    302 #define DEFINE_RPC_CLASS(Class, STRUCT) \
    303 class Class : public Noncopyable {\
    304 public: \
    305     Class() \
    306     { \
    307         m_className = #Class; \
    308     } \
    309     virtual ~Class() { } \
    310     \
    311     STRUCT( \
    312         TOOLS_RPC_API_METHOD0, \
    313         TOOLS_RPC_API_METHOD1, \
    314         TOOLS_RPC_API_METHOD2, \
    315         TOOLS_RPC_API_METHOD3, \
    316         TOOLS_RPC_API_METHOD4, \
    317         TOOLS_RPC_API_METHOD5) \
    318     WebCore::String m_className; \
    319 }; \
    320 \
    321 class Class##Stub \
    322     : public Class \
    323     , public DevToolsRPC { \
    324 public: \
    325     explicit Class##Stub(Delegate* delegate) : DevToolsRPC(delegate) { } \
    326     virtual ~Class##Stub() { } \
    327     typedef Class CLASS; \
    328     STRUCT( \
    329         TOOLS_RPC_STUB_METHOD0, \
    330         TOOLS_RPC_STUB_METHOD1, \
    331         TOOLS_RPC_STUB_METHOD2, \
    332         TOOLS_RPC_STUB_METHOD3, \
    333         TOOLS_RPC_STUB_METHOD4, \
    334         TOOLS_RPC_STUB_METHOD5) \
    335 }; \
    336 \
    337 class Class##Dispatch : public Noncopyable { \
    338 public: \
    339     Class##Dispatch() { } \
    340     virtual ~Class##Dispatch() { } \
    341     \
    342     static bool dispatch(Class* delegate, \
    343                          const WebKit::WebDevToolsMessageData& data) { \
    344         String className = data.className; \
    345         if (className != #Class) \
    346             return false; \
    347         String methodName = data.methodName; \
    348         Vector<String> args; \
    349         for (size_t i = 0; i < data.arguments.size(); i++) \
    350             args.append(data.arguments[i]); \
    351         typedef Class CLASS; \
    352         STRUCT( \
    353             TOOLS_RPC_DISPATCH0, \
    354             TOOLS_RPC_DISPATCH1, \
    355             TOOLS_RPC_DISPATCH2, \
    356             TOOLS_RPC_DISPATCH3, \
    357             TOOLS_RPC_DISPATCH4, \
    358             TOOLS_RPC_DISPATCH5) \
    359         return false; \
    360     } \
    361 };
    362 
    363 ///////////////////////////////////////////////////////
    364 // RPC base class
    365 class DevToolsRPC {
    366 public:
    367     class Delegate {
    368     public:
    369         Delegate() { }
    370         virtual ~Delegate() { }
    371         virtual void sendRpcMessage(const WebKit::WebDevToolsMessageData& data) = 0;
    372     };
    373 
    374     explicit DevToolsRPC(Delegate* delegate) : m_delegate(delegate) { }
    375     virtual ~DevToolsRPC() { };
    376 
    377 protected:
    378     void sendRpcMessage(const String& className,
    379                         const String& methodName,
    380                         const Vector<String>& args) {
    381       WebKit::WebVector<WebKit::WebString> webArgs(args.size());
    382       for (size_t i = 0; i < args.size(); i++)
    383           webArgs[i] = args[i];
    384       WebKit::WebDevToolsMessageData data;
    385       data.className = className;
    386       data.methodName = methodName;
    387       data.arguments.swap(webArgs);
    388       this->m_delegate->sendRpcMessage(data);
    389     }
    390 
    391     Delegate* m_delegate;
    392 };
    393 
    394 } // namespace WebKit
    395 
    396 #endif
    397