|
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 |