1 
2 /*
3  Copyright (c) 2013, Oracle and/or its affiliates. All rights
4  reserved.
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License, version 2.0,
8  as published by the Free Software Foundation.
9 
10  This program is also distributed with certain software (including
11  but not limited to OpenSSL) that is licensed under separate terms,
12  as designated in a particular file or component or in included license
13  documentation.  The authors of MySQL hereby grant you an additional
14  permission to link the program and your derivative works with the
15  separately licensed software that they have included with MySQL.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  GNU General Public License, version 2.0, for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25  02110-1301  USA
26  */
27 
28 #ifndef NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H
29 #define NODEJS_ADAPTER_INCLUDE_ASYNCMETHODCALL_H
30 #include <assert.h>
31 
32 #include "JsConverter.h"
33 #include "async_common.h"
34 #include "common_v8_values.h"
35 
36 using namespace v8;
37 
38 
39 /** These classes wrap various sorts of C and C++ functions for use as either
40   * synchronous or asynchronous JavaScript methods.
41   *
42   * There are two class hierarchies declared here.
43   * The first hierarchy is:
44   *    AsyncCall
45   *     -> Call_Returning<R>           template over return type
46   *       -> NativeMethodCall<R, C>      template over class
47   *
48   * The second hierarchy is a set of alternate classes
49   *     Call_1_<A0> , Call_2_<A0,A1> , ..  Call_8_<A0,A1, .. A7>
50   *     expressing the set of arguments to a function or method call
51   *
52   * The base class AsyncCall wraps the worker-thread run() routine and the
53   * main thread (post-run) doAsyncCallback() needed for async execution.
54   *
55   * The run() method, declared void run(void), will be scheduled to run in a
56   * uv worker thread.
57   *
58   * The doAsyncCallback() method will take a JavaScript context.  It is expected
59   * to prepare the result and call the user's callback function.
60   *
61   * The templated class AsyncCall_Returning<R> inherits from AsyncCall and
62   * adds a return type, which is initialized at 0.
63   *
64   * OTHER NOTES:
65   *   The standard AsyncCall constructor allocates a persistent V8 object, so
66   *   it can only run in the main JavaScript thread.
67   *   However, the constructor for AsyncAsyncCall runs in a UV worker thread,
68   *   so there is an alternative chain of protected constructors from
69   *   AsyncAsyncCall up to AsyncCall.
70   */
71 
72 
73 /** Base class
74 **/
75 class AsyncCall {
76   protected:
77     /* Member variables */
78     Persistent<Function> callback;
79 
80     /* Protected constructor chain from AsyncAsyncCall */
AsyncCall(Persistent<Function> cb)81     AsyncCall(Persistent<Function> cb) : callback(cb) {};
82 
83   public:
AsyncCall(Local<Value> callbackFunc)84     AsyncCall(Local<Value> callbackFunc) {
85       callback = Persistent<Function>::New(Local<Function>::Cast(callbackFunc));
86     }
87 
88     /* Destructor */
~AsyncCall()89     virtual ~AsyncCall() {
90       callback.Dispose();
91     }
92 
93     /* Methods (Pure virtual) */
94     virtual void run(void) = 0;
95     virtual void doAsyncCallback(Local<Object>) = 0;
96 
97     /* Base Class Virtual Methods */
handleErrors(void)98     virtual void handleErrors(void) { }
99 
100     /* Base Class Fixed Methods */
runAsync()101     void runAsync() {
102       if (callback->IsCallable()) {
103         uv_work_t * req = new uv_work_t;
104         req->data = (void *) this;
105         uv_queue_work(uv_default_loop(), req, work_thd_run, main_thd_complete);
106       }
107       else {
108         ThrowException(Exception::TypeError(String::New("Uncallable Callback")));
109       }
110     }
111 };
112 
113 
114 /** First-level template class;
115     templated over return types
116 **/
117 template <typename RETURN_TYPE>
118 class AsyncCall_Returning : public AsyncCall {
119 private:
120   /* Private Member variables */
121   Envelope * returnValueEnvelope;
122 
123 protected:
124   /* Protected Constructor Chain */
125   AsyncCall_Returning<RETURN_TYPE>(Persistent<Function> callback) :
AsyncCall(callback)126     AsyncCall(callback), returnValueEnvelope(0), error(0)  {}
127 
128 public:
129   /* Member variables */
130   NativeCodeError *error;
131   RETURN_TYPE return_val;
132 
133   /* Constructors */
134   AsyncCall_Returning<RETURN_TYPE>(Local<Value> callback) :
AsyncCall(callback)135     AsyncCall(callback), returnValueEnvelope(0), error(0)  {}
136 
137   AsyncCall_Returning<RETURN_TYPE>(Local<Value> callback, RETURN_TYPE rv) :
AsyncCall(callback)138     AsyncCall(callback), returnValueEnvelope(0), error(0), return_val(rv)    {}
139 
140   /* Destructor */
141   virtual ~AsyncCall_Returning<RETURN_TYPE>() {
142     if(error) delete error;
143   }
144 
145   /* Methods */
wrapReturnValueAs(Envelope * env)146   void wrapReturnValueAs(Envelope *env) {
147     returnValueEnvelope = env;
148   }
149 
jsReturnVal()150   Local<Value> jsReturnVal() {
151     HandleScope scope;
152 
153     if(isWrappedPointer(return_val)) {
154       DEBUG_ASSERT(returnValueEnvelope);
155       Local<Object> obj = returnValueEnvelope->newWrapper();
156       wrapPointerInObject(return_val, *returnValueEnvelope, obj);
157       return scope.Close(obj);
158     }
159     else {
160       /* Optimization for a common case */
161       if(return_val == 0) {
162         return scope.Close(Zero());
163       } else {
164         return scope.Close(toJS(return_val));
165       }
166     }
167   }
168 
169   /* doAsyncCallback() is an async callback, run by main_thread_complete().
170   */
doAsyncCallback(Local<Object> context)171   void doAsyncCallback(Local<Object> context) {
172     HandleScope scope;
173     Handle<Value> cb_args[2];
174 
175     if(error) cb_args[0] = error->toJS();
176     else      cb_args[0] = Null();
177 
178     cb_args[1] = jsReturnVal();
179 
180     callback->Call(context, 2, cb_args);
181   }
182 };
183 
184 
185 /** Second-level template class for C++ method calls:
186     templated over class of native object.
187     This class is the home of error handling for C++ code.
188 **/
189 template <typename R, typename C>
190 class NativeMethodCall : public AsyncCall_Returning<R> {
191 public:
192   /* Member variables */
193   typedef NativeCodeError * (*errorHandler_fn_t)(R, C *);
194   C * native_obj;
195   errorHandler_fn_t errorHandler;
196 
197   /* Constructor */
198   NativeMethodCall<R, C>(const Arguments &args, int callback_idx) :
199     AsyncCall_Returning<R>(args[callback_idx]),  /*callback*/
200     errorHandler(0)
201   {
202     native_obj = unwrapPointer<C *>(args.Holder());
203     DEBUG_ASSERT(native_obj != NULL);
204   }
205 
206   /* Methods */
handleErrors(void)207   void handleErrors(void) {
208     if(errorHandler) AsyncCall_Returning<R>::error =
209       errorHandler(AsyncCall_Returning<R>::return_val, native_obj);
210   }
211 
212 protected:
213   /* Alternative constructor used only by AsyncAsyncCall */
214   NativeMethodCall<R, C>(C * obj,
215                          Persistent<Function> callback,
216                          errorHandler_fn_t errHandler) :
217     AsyncCall_Returning<R>(callback),
218     native_obj(obj),
219     errorHandler(errHandler)                                {};
220 };
221 
222 
223 /** AsyncAsyncCall is used to wrap returns from NDB Asynchronoous APIs.
224 **/
225 template <typename R, typename C>
226 class AsyncAsyncCall : public NativeMethodCall<R, C> {
227 public:
228   typedef NativeCodeError * (*errorHandler_fn_t)(R, C *);
229 
230   /* Constructor */
231   AsyncAsyncCall<R, C>(C * obj, Persistent<Function> callback,
232                        errorHandler_fn_t errHandler) :
233     NativeMethodCall<R, C>(obj, callback, errHandler)       {};
234 
235   /* Methods */
run(void)236   void run(void) {};
237 };
238 
239 
240 /** Alternate second-level template class for calls returning void.
241     No error handling here.
242 **/
243 template <typename C>
244 class NativeVoidMethodCall : public AsyncCall_Returning<int> {
245 public:
246   /* Member variables */
247   C * native_obj;
248 
249   /* Constructor */
250   NativeVoidMethodCall<C>(const Arguments &args, int callback_idx) :
251     AsyncCall_Returning<int>(args[callback_idx], 1)  /*callback*/
252   {
253     native_obj = unwrapPointer<C *>(args.Holder());
254     DEBUG_ASSERT(native_obj != NULL);
255   }
256 };
257 
258 
259 /** Base class templated over arguments
260 */
261 template <typename A0, typename A1, typename A2, typename A3,
262           typename A4, typename A5, typename A6, typename A7>
263 class Call_8_ {
264 public:
265   /* Member variables */
266   JsValueConverter<A0> arg0converter;       A0 arg0;
267   JsValueConverter<A1> arg1converter;       A1 arg1;
268   JsValueConverter<A2> arg2converter;       A2 arg2;
269   JsValueConverter<A3> arg3converter;       A3 arg3;
270   JsValueConverter<A4> arg4converter;       A4 arg4;
271   JsValueConverter<A5> arg5converter;       A5 arg5;
272   JsValueConverter<A6> arg6converter;       A6 arg6;
273   JsValueConverter<A7> arg7converter;       A7 arg7;
274 
275   /* Constructor */
276   Call_8_<A0, A1, A2, A3, A4, A5, A6, A7>(const Arguments &args) :
arg0converter(args[0])277     arg0converter(args[0]),
278     arg1converter(args[1]),
279     arg2converter(args[2]),
280     arg3converter(args[3]),
281     arg4converter(args[4]),
282     arg5converter(args[5]),
283     arg6converter(args[6]),
284     arg7converter(args[7])
285   {
286     arg0 = arg0converter.toC();
287     arg1 = arg1converter.toC();
288     arg2 = arg2converter.toC();
289     arg3 = arg3converter.toC();
290     arg4 = arg4converter.toC();
291     arg5 = arg5converter.toC();
292     arg6 = arg6converter.toC();
293     arg7 = arg7converter.toC();
294   }
295 };
296 
297 
298 template <typename A0, typename A1, typename A2, typename A3,
299           typename A4, typename A5, typename A6>
300 class Call_7_ {
301 public:
302   /* Member variables */
303   JsValueConverter<A0> arg0converter;       A0 arg0;
304   JsValueConverter<A1> arg1converter;       A1 arg1;
305   JsValueConverter<A2> arg2converter;       A2 arg2;
306   JsValueConverter<A3> arg3converter;       A3 arg3;
307   JsValueConverter<A4> arg4converter;       A4 arg4;
308   JsValueConverter<A5> arg5converter;       A5 arg5;
309   JsValueConverter<A6> arg6converter;       A6 arg6;
310 
311   /* Constructor */
312   Call_7_<A0, A1, A2, A3, A4, A5, A6>(const Arguments &args) :
arg0converter(args[0])313     arg0converter(args[0]),
314     arg1converter(args[1]),
315     arg2converter(args[2]),
316     arg3converter(args[3]),
317     arg4converter(args[4]),
318     arg5converter(args[5]),
319     arg6converter(args[6])
320   {
321     arg0 = arg0converter.toC();
322     arg1 = arg1converter.toC();
323     arg2 = arg2converter.toC();
324     arg3 = arg3converter.toC();
325     arg4 = arg4converter.toC();
326     arg5 = arg5converter.toC();
327     arg6 = arg6converter.toC();
328   }
329 };
330 
331 
332 template <typename A0, typename A1, typename A2, typename A3,
333           typename A4, typename A5>
334 class Call_6_ {
335 public:
336   /* Member variables */
337   JsValueConverter<A0> arg0converter;       A0 arg0;
338   JsValueConverter<A1> arg1converter;       A1 arg1;
339   JsValueConverter<A2> arg2converter;       A2 arg2;
340   JsValueConverter<A3> arg3converter;       A3 arg3;
341   JsValueConverter<A4> arg4converter;       A4 arg4;
342   JsValueConverter<A5> arg5converter;       A5 arg5;
343 
344   /* Constructor */
345   Call_6_<A0, A1, A2, A3, A4, A5>(const Arguments &args) :
arg0converter(args[0])346     arg0converter(args[0]),
347     arg1converter(args[1]),
348     arg2converter(args[2]),
349     arg3converter(args[3]),
350     arg4converter(args[4]),
351     arg5converter(args[5])
352   {
353     arg0 = arg0converter.toC();
354     arg1 = arg1converter.toC();
355     arg2 = arg2converter.toC();
356     arg3 = arg3converter.toC();
357     arg4 = arg4converter.toC();
358     arg5 = arg5converter.toC();
359   }
360 };
361 
362 
363 template <typename A0, typename A1, typename A2, typename A3, typename A4>
364 class Call_5_ {
365 public:
366   /* Member variables */
367   JsValueConverter<A0> arg0converter;       A0 arg0;
368   JsValueConverter<A1> arg1converter;       A1 arg1;
369   JsValueConverter<A2> arg2converter;       A2 arg2;
370   JsValueConverter<A3> arg3converter;       A3 arg3;
371   JsValueConverter<A4> arg4converter;       A4 arg4;
372 
373   /* Constructor */
374   Call_5_<A0, A1, A2, A3, A4>(const Arguments &args) :
arg0converter(args[0])375     arg0converter(args[0]),
376     arg1converter(args[1]),
377     arg2converter(args[2]),
378     arg3converter(args[3]),
379     arg4converter(args[4])
380   {
381     arg0 = arg0converter.toC();
382     arg1 = arg1converter.toC();
383     arg2 = arg2converter.toC();
384     arg3 = arg3converter.toC();
385     arg4 = arg4converter.toC();
386   }
387 };
388 
389 
390 template <typename A0, typename A1, typename A2, typename A3>
391 class Call_4_ {
392 public:
393   /* Member variables */
394   JsValueConverter<A0> arg0converter;       A0 arg0;
395   JsValueConverter<A1> arg1converter;       A1 arg1;
396   JsValueConverter<A2> arg2converter;       A2 arg2;
397   JsValueConverter<A3> arg3converter;       A3 arg3;
398 
399   /* Constructor */
400   Call_4_<A0, A1, A2, A3>(const Arguments &args) :
arg0converter(args[0])401     arg0converter(args[0]),
402     arg1converter(args[1]),
403     arg2converter(args[2]),
404     arg3converter(args[3])
405   {
406     arg0 = arg0converter.toC();
407     arg1 = arg1converter.toC();
408     arg2 = arg2converter.toC();
409     arg3 = arg3converter.toC();
410   }
411 };
412 
413 
414 template <typename A0, typename A1, typename A2>
415 class Call_3_ {
416 public:
417   /* Member variables */
418   JsValueConverter<A0> arg0converter;       A0 arg0;
419   JsValueConverter<A1> arg1converter;       A1 arg1;
420   JsValueConverter<A2> arg2converter;       A2 arg2;
421 
422   /* Constructor */
423   Call_3_<A0, A1, A2>(const Arguments &args) :
arg0converter(args[0])424     arg0converter(args[0]),
425     arg1converter(args[1]),
426     arg2converter(args[2])
427   {
428     arg0 = arg0converter.toC();
429     arg1 = arg1converter.toC();
430     arg2 = arg2converter.toC();
431   }
432 };
433 
434 
435 template <typename A0, typename A1>
436 class Call_2_ {
437 public:
438   /* Member variables */
439   JsValueConverter<A0> arg0converter;       A0 arg0;
440   JsValueConverter<A1> arg1converter;       A1 arg1;
441 
442   /* Constructor */
443   Call_2_<A0, A1>(const Arguments &args) :
arg0converter(args[0])444     arg0converter(args[0]),
445     arg1converter(args[1])
446   {
447     arg0 = arg0converter.toC();
448     arg1 = arg1converter.toC();
449   }
450 };
451 
452 
453 template <typename A0>
454 class Call_1_ {
455 public:
456   /* Member variables */
457   JsValueConverter<A0> arg0converter;       A0 arg0;
458 
459   /* Constructor */
460   Call_1_<A0>(const Arguments &args) :
arg0converter(args[0])461     arg0converter(args[0])
462   {
463     arg0 = arg0converter.toC();
464   }
465 };
466 
467 #endif
468