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