generate_java_rpc.cpp revision 2c5eb269bb047d3fdfc05e852f158563a3de6df8
1#include "generate_java.h"
2#include "Type.h"
3#include <string.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
9        "Context", Type::BUILT_IN, false, false, false);
10Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.service",
11        "AndroidAtHomePresenter", Type::BUILT_IN, false, false, false);
12Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.service",
13        "AndroidAtHomePresenter.Listener", Type::BUILT_IN, false, false, false);
14Type* RPC_BROKER_TYPE = new Type("com.android.athome.utils", "AndroidAtHomeBroker",
15        Type::BUILT_IN, false, false, false);
16Type* RPC_SERVICE_BASE_TYPE = new Type("com.android.athome.service", "AndroidAtHomeService",
17        Type::BUILT_IN, false, false, false);
18Type* RPC_SERVICE_INFO_TYPE = new ParcelableType("com.android.athome.stubs",
19        "AndroidAtHomeServiceInfo", true, __FILE__, __LINE__);
20Type* RPC_RESULT_HANDLER_TYPE = new ParcelableType("com.android.athome.rpc", "RpcResultHandler",
21        true, __FILE__, __LINE__);
22Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
23        Type::BUILT_IN, false, false, false);
24Type* RPC_CONTEXT_TYPE = new ParcelableType("com.android.athome.rpc", "RpcContext", true,
25        __FILE__, __LINE__);
26
27static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
28        Variable* v, Variable* data, Variable** cl);
29static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
30static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
31        Variable* data);
32
33static string
34format_int(int n)
35{
36    char str[20];
37    sprintf(str, "%d", n);
38    return string(str);
39}
40
41static string
42class_name_leaf(const string& str)
43{
44    string::size_type pos = str.rfind('.');
45    if (pos == string::npos) {
46        return str;
47    } else {
48        return string(str, pos+1);
49    }
50}
51
52static string
53results_class_name(const string& n)
54{
55    string str = n;
56    str[0] = toupper(str[0]);
57    str.insert(0, "On");
58    return str;
59}
60
61static string
62results_method_name(const string& n)
63{
64    string str = n;
65    str[0] = toupper(str[0]);
66    str.insert(0, "on");
67    return str;
68}
69
70static string
71push_method_name(const string& n)
72{
73    string str = n;
74    str[0] = toupper(str[0]);
75    str.insert(0, "push");
76    return str;
77}
78
79// =================================================
80class DispatcherClass : public Class
81{
82public:
83    DispatcherClass(const interface_type* iface, Expression* target);
84    virtual ~DispatcherClass();
85
86    void AddMethod(const method_type* method);
87    void DoneWithMethods();
88
89    Method* processMethod;
90    Variable* actionParam;
91    Variable* requestParam;
92    Variable* rpcContextParam;
93    Variable* errorParam;
94    Variable* requestData;
95    Variable* resultData;
96    IfStatement* dispatchIfStatement;
97    Expression* targetExpression;
98
99private:
100    void generate_process();
101};
102
103DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
104    :Class(),
105     dispatchIfStatement(NULL),
106     targetExpression(target)
107{
108    generate_process();
109}
110
111DispatcherClass::~DispatcherClass()
112{
113}
114
115void
116DispatcherClass::generate_process()
117{
118    // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
119    this->processMethod = new Method;
120        this->processMethod->modifiers = PUBLIC;
121        this->processMethod->returnType = BYTE_TYPE;
122        this->processMethod->returnTypeDimension = 1;
123        this->processMethod->name = "process";
124        this->processMethod->statements = new StatementBlock;
125
126    this->actionParam = new Variable(STRING_TYPE, "action");
127    this->processMethod->parameters.push_back(this->actionParam);
128
129    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
130    this->processMethod->parameters.push_back(this->requestParam);
131
132    this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
133    this->processMethod->parameters.push_back(this->rpcContextParam);
134
135    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
136    this->processMethod->parameters.push_back(this->errorParam);
137
138    this->requestData = new Variable(RPC_DATA_TYPE, "request");
139    this->processMethod->statements->Add(new VariableDeclaration(requestData,
140                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
141
142    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
143    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
144                NULL_VALUE));
145}
146
147void
148DispatcherClass::AddMethod(const method_type* method)
149{
150    arg_type* arg;
151
152    // The if/switch statement
153    IfStatement* ifs = new IfStatement();
154        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
155                1, this->actionParam);
156    StatementBlock* block = ifs->statements = new StatementBlock;
157    if (this->dispatchIfStatement == NULL) {
158        this->dispatchIfStatement = ifs;
159        this->processMethod->statements->Add(dispatchIfStatement);
160    } else {
161        this->dispatchIfStatement->elseif = ifs;
162        this->dispatchIfStatement = ifs;
163    }
164
165    // The call to decl (from above)
166    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
167
168    // args
169    Variable* classLoader = NULL;
170    VariableFactory stubArgs("_arg");
171    arg = method->args;
172    while (arg != NULL) {
173        Type* t = NAMES.Search(arg->type.type.data);
174        Variable* v = stubArgs.Get(t);
175        v->dimension = arg->type.dimension;
176
177        // Unmarshall the parameter
178        block->Add(new VariableDeclaration(v));
179        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
180            generate_create_from_data(t, block, arg->name.data, v,
181                    this->requestData, &classLoader);
182        } else {
183            if (arg->type.dimension == 0) {
184                block->Add(new Assignment(v, new NewExpression(v->type)));
185            }
186            else if (arg->type.dimension == 1) {
187                generate_new_array(v->type, block, v, this->requestData);
188            }
189            else {
190                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
191                        __LINE__);
192            }
193        }
194
195        // Add that parameter to the method call
196        realCall->arguments.push_back(v);
197
198        arg = arg->next;
199    }
200
201    // Add a final parameter: RpcContext. Contains data about
202    // incoming request (e.g., certificate)
203    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
204
205    Type* returnType = NAMES.Search(method->type.type.data);
206    if (returnType == EVENT_FAKE_TYPE) {
207        returnType = VOID_TYPE;
208    }
209
210    // the real call
211    bool first = true;
212    Variable* _result = NULL;
213    if (returnType == VOID_TYPE) {
214        block->Add(realCall);
215    } else {
216        _result = new Variable(returnType, "_result",
217                                method->type.dimension);
218        block->Add(new VariableDeclaration(_result, realCall));
219
220        // need the result RpcData
221        if (first) {
222            block->Add(new Assignment(this->resultData,
223                        new NewExpression(RPC_DATA_TYPE)));
224            first = false;
225        }
226
227        // marshall the return value
228        generate_write_to_data(returnType, block,
229                new StringLiteralExpression("_result"), _result, this->resultData);
230    }
231
232    // out parameters
233    int i = 0;
234    arg = method->args;
235    while (arg != NULL) {
236        Type* t = NAMES.Search(arg->type.type.data);
237        Variable* v = stubArgs.Get(i++);
238
239        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
240            // need the result RpcData
241            if (first) {
242                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
243                first = false;
244            }
245
246            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
247                    v, this->resultData);
248        }
249
250        arg = arg->next;
251    }
252}
253
254void
255DispatcherClass::DoneWithMethods()
256{
257    if (this->dispatchIfStatement == NULL) {
258        return;
259    }
260
261    this->elements.push_back(this->processMethod);
262
263    IfStatement* fallthrough = new IfStatement();
264        fallthrough->statements = new StatementBlock;
265        fallthrough->statements->Add(new ReturnStatement(
266                    new MethodCall(SUPER_VALUE, "process", 4,
267                    this->actionParam, this->requestParam,
268                    this->rpcContextParam,
269                    this->errorParam)));
270    this->dispatchIfStatement->elseif = fallthrough;
271    IfStatement* s = new IfStatement;
272        s->statements = new StatementBlock;
273    this->processMethod->statements->Add(s);
274    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
275    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
276    s->elseif = new IfStatement;
277    s = s->elseif;
278    s->statements->Add(new ReturnStatement(NULL_VALUE));
279}
280
281// =================================================
282class RpcProxyClass : public Class
283{
284public:
285    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
286    virtual ~RpcProxyClass();
287
288    Variable* endpoint;
289    Variable* context;
290
291private:
292    void generate_ctor();
293};
294
295RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
296    :Class()
297{
298    this->comment = gather_comments(iface->comments_token->extra);
299    this->modifiers = PUBLIC;
300    this->what = Class::CLASS;
301    this->type = interfaceType;
302
303    // context
304    this->context = new Variable(CONTEXT_TYPE, "_context");
305    this->elements.push_back(new Field(PRIVATE, this->context));
306    // endpoint
307    this->endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "_endpoint");
308    this->elements.push_back(new Field(PRIVATE, this->endpoint));
309
310    // methods
311    generate_ctor();
312}
313
314RpcProxyClass::~RpcProxyClass()
315{
316}
317
318void
319RpcProxyClass::generate_ctor()
320{
321    Variable* context = new Variable(CONTEXT_TYPE, "context");
322    Variable* endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "endpoint");
323    Method* ctor = new Method;
324        ctor->modifiers = PUBLIC;
325        ctor->name = class_name_leaf(this->type->Name());
326        ctor->statements = new StatementBlock;
327        ctor->parameters.push_back(context);
328        ctor->parameters.push_back(endpoint);
329    this->elements.push_back(ctor);
330
331    ctor->statements->Add(new Assignment(this->context, context));
332    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
333}
334
335// =================================================
336class PresenterClass : public DispatcherClass
337{
338public:
339    PresenterClass(const interface_type* iface, Type* listenerType);
340    virtual ~PresenterClass();
341
342    Variable* _listener;
343
344private:
345    void generate_ctor();
346};
347
348Expression*
349generate_get_listener_expression(Type* cast)
350{
351    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
352}
353
354PresenterClass::PresenterClass(const interface_type* iface, Type* listenerType)
355    :DispatcherClass(iface, generate_get_listener_expression(listenerType))
356{
357    this->modifiers = PRIVATE;
358    this->what = Class::CLASS;
359    this->type = new Type(iface->package ? iface->package : "",
360                        append(iface->name.data, ".Presenter"),
361                        Type::GENERATED, false, false, false);
362    this->extends = PRESENTER_BASE_TYPE;
363
364    this->_listener = new Variable(listenerType, "_listener");
365    this->elements.push_back(new Field(PRIVATE, this->_listener));
366
367    // methods
368    generate_ctor();
369}
370
371PresenterClass::~PresenterClass()
372{
373}
374
375void
376PresenterClass::generate_ctor()
377{
378    Variable* context = new Variable(CONTEXT_TYPE, "context");
379    Variable* endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "endpoint");
380    Variable* listener = new Variable(this->_listener->type, "listener");
381    Method* ctor = new Method;
382        ctor->modifiers = PUBLIC;
383        ctor->name = class_name_leaf(this->type->Name());
384        ctor->statements = new StatementBlock;
385        ctor->parameters.push_back(context);
386        ctor->parameters.push_back(endpoint);
387        ctor->parameters.push_back(listener);
388    this->elements.push_back(ctor);
389
390    ctor->statements->Add(new MethodCall("super", 3, context, endpoint, listener));
391    ctor->statements->Add(new Assignment(this->_listener, listener));
392}
393
394// =================================================
395class ListenerClass : public Class
396{
397public:
398    ListenerClass(const interface_type* iface);
399    virtual ~ListenerClass();
400
401    bool needed;
402
403private:
404    void generate_ctor();
405};
406
407ListenerClass::ListenerClass(const interface_type* iface)
408    :Class(),
409     needed(false)
410{
411    this->comment = "/** Extend this to listen to the events from this class. */";
412    this->modifiers = STATIC | PUBLIC ;
413    this->what = Class::CLASS;
414    this->type = new Type(iface->package ? iface->package : "",
415                        append(iface->name.data, ".Listener"),
416                        Type::GENERATED, false, false, false);
417    this->extends = PRESENTER_LISTENER_BASE_TYPE;
418}
419
420ListenerClass::~ListenerClass()
421{
422}
423
424// =================================================
425class ServiceBaseClass : public DispatcherClass
426{
427public:
428    ServiceBaseClass(const interface_type* iface);
429    virtual ~ServiceBaseClass();
430
431    bool needed;
432
433private:
434    void generate_ctor();
435};
436
437ServiceBaseClass::ServiceBaseClass(const interface_type* iface)
438    :DispatcherClass(iface, THIS_VALUE),
439     needed(false)
440{
441    this->comment = "/** Extend this to implement a link service. */";
442    this->modifiers = STATIC | PUBLIC | ABSTRACT;
443    this->what = Class::CLASS;
444    this->type = new Type(iface->package ? iface->package : "",
445                        append(iface->name.data, ".ServiceBase"),
446                        Type::GENERATED, false, false, false);
447    this->extends = RPC_SERVICE_BASE_TYPE;
448
449    // methods
450    generate_ctor();
451}
452
453ServiceBaseClass::~ServiceBaseClass()
454{
455}
456
457void
458ServiceBaseClass::generate_ctor()
459{
460    Variable* context = new Variable(SERVICE_CONTEXT_TYPE, "context");
461    Variable* name = new Variable(STRING_TYPE, "name");
462    Variable* type = new Variable(STRING_TYPE, "type");
463    Variable* version = new Variable(INT_TYPE, "version");
464    Method* ctor = new Method;
465        ctor->modifiers = PUBLIC;
466        ctor->name = class_name_leaf(this->type->Name());
467        ctor->statements = new StatementBlock;
468        ctor->parameters.push_back(context);
469        ctor->parameters.push_back(name);
470        ctor->parameters.push_back(type);
471        ctor->parameters.push_back(version);
472    this->elements.push_back(ctor);
473
474    ctor->statements->Add(new MethodCall("super", 4, context, name, type, version));
475}
476
477// =================================================
478class ResultDispatcherClass : public Class
479{
480public:
481    ResultDispatcherClass();
482    virtual ~ResultDispatcherClass();
483
484    void AddMethod(int index, const string& name, Method** method, Variable** param);
485
486    bool needed;
487    Variable* methodId;
488    Variable* callback;
489    Method* onResultMethod;
490    Variable* resultParam;
491    SwitchStatement* methodSwitch;
492
493private:
494    void generate_ctor();
495    void generate_onResult();
496};
497
498ResultDispatcherClass::ResultDispatcherClass()
499    :Class(),
500     needed(false)
501{
502    this->modifiers = PRIVATE | FINAL;
503    this->what = Class::CLASS;
504    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
505    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
506
507    // methodId
508    this->methodId = new Variable(INT_TYPE, "methodId");
509    this->elements.push_back(new Field(PRIVATE, this->methodId));
510    this->callback = new Variable(OBJECT_TYPE, "callback");
511    this->elements.push_back(new Field(PRIVATE, this->callback));
512
513    // methods
514    generate_ctor();
515    generate_onResult();
516}
517
518ResultDispatcherClass::~ResultDispatcherClass()
519{
520}
521
522void
523ResultDispatcherClass::generate_ctor()
524{
525    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
526    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
527    Method* ctor = new Method;
528        ctor->modifiers = PUBLIC;
529        ctor->name = class_name_leaf(this->type->Name());
530        ctor->statements = new StatementBlock;
531        ctor->parameters.push_back(methodIdParam);
532        ctor->parameters.push_back(callbackParam);
533    this->elements.push_back(ctor);
534
535    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
536    ctor->statements->Add(new Assignment(this->callback, callbackParam));
537}
538
539void
540ResultDispatcherClass::generate_onResult()
541{
542    this->onResultMethod = new Method;
543        this->onResultMethod->modifiers = PUBLIC;
544        this->onResultMethod->returnType = VOID_TYPE;
545        this->onResultMethod->returnTypeDimension = 0;
546        this->onResultMethod->name = "onResult";
547        this->onResultMethod->statements = new StatementBlock;
548    this->elements.push_back(this->onResultMethod);
549
550    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
551    this->onResultMethod->parameters.push_back(this->resultParam);
552
553    this->methodSwitch = new SwitchStatement(this->methodId);
554    this->onResultMethod->statements->Add(this->methodSwitch);
555}
556
557void
558ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
559{
560    Method* m = new Method;
561        m->modifiers = PUBLIC;
562        m->returnType = VOID_TYPE;
563        m->returnTypeDimension = 0;
564        m->name = name;
565        m->statements = new StatementBlock;
566    *param = new Variable(BYTE_TYPE, "result", 1);
567    m->parameters.push_back(*param);
568    this->elements.push_back(m);
569    *method = m;
570
571    Case* c = new Case(format_int(index));
572    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
573    c->statements->Add(new Break());
574
575    this->methodSwitch->cases.push_back(c);
576}
577
578// =================================================
579static void
580generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
581{
582    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
583    exit(1);
584}
585
586static void
587generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
588                            Variable* data, Variable** cl)
589{
590    Expression* k = new StringLiteralExpression(key);
591    if (v->dimension == 0) {
592        t->CreateFromRpcData(addTo, k, v, data, cl);
593    }
594    if (v->dimension == 1) {
595        //t->ReadArrayFromRpcData(addTo, v, data, cl);
596        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
597                __FILE__, __LINE__);
598    }
599}
600
601static void
602generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
603{
604    if (v->dimension == 0) {
605        t->WriteToRpcData(addTo, k, v, data, 0);
606    }
607    if (v->dimension == 1) {
608        //t->WriteArrayToParcel(addTo, v, data);
609        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
610                __FILE__, __LINE__);
611    }
612}
613
614// =================================================
615static Type*
616generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
617{
618    arg_type* arg;
619
620    string resultsMethodName = results_method_name(method->name.data);
621    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
622            Type::GENERATED, false, false, false);
623
624    if (!method->oneway) {
625        Class* resultsClass = new Class;
626            resultsClass->modifiers = STATIC | PUBLIC;
627            resultsClass->what = Class::INTERFACE;
628            resultsClass->type = resultsInterfaceType;
629
630        Method* resultMethod = new Method;
631            resultMethod->comment = gather_comments(method->comments_token->extra);
632            resultMethod->modifiers = PUBLIC;
633            resultMethod->returnType = VOID_TYPE;
634            resultMethod->returnTypeDimension = 0;
635            resultMethod->name = resultsMethodName;
636        if (0 != strcmp("void", method->type.type.data)) {
637            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
638                        "_result", method->type.dimension));
639        }
640        arg = method->args;
641        while (arg != NULL) {
642            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
643                resultMethod->parameters.push_back(new Variable(
644                                    NAMES.Search(arg->type.type.data), arg->name.data,
645                                    arg->type.dimension));
646            }
647            arg = arg->next;
648        }
649        resultsClass->elements.push_back(resultMethod);
650
651        if (resultMethod->parameters.size() > 0) {
652            proxyClass->elements.push_back(resultsClass);
653            return resultsInterfaceType;
654        }
655    }
656    //delete resultsInterfaceType;
657    return NULL;
658}
659
660static void
661generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
662        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
663{
664    arg_type* arg;
665    Method* proxyMethod = new Method;
666        proxyMethod->comment = gather_comments(method->comments_token->extra);
667        proxyMethod->modifiers = PUBLIC;
668        proxyMethod->returnType = VOID_TYPE;
669        proxyMethod->returnTypeDimension = 0;
670        proxyMethod->name = method->name.data;
671        proxyMethod->statements = new StatementBlock;
672    proxyClass->elements.push_back(proxyMethod);
673
674    // The local variables
675    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
676    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
677
678    // Add the arguments
679    arg = method->args;
680    while (arg != NULL) {
681        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
682            // Function signature
683            Type* t = NAMES.Search(arg->type.type.data);
684            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
685            proxyMethod->parameters.push_back(v);
686
687            // Input parameter marshalling
688            generate_write_to_data(t, proxyMethod->statements,
689                    new StringLiteralExpression(arg->name.data), v, _data);
690        }
691        arg = arg->next;
692    }
693
694    // If there is a results interface for this class
695    Expression* resultParameter;
696    if (resultsInterfaceType != NULL) {
697        // Result interface parameter
698        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
699        proxyMethod->parameters.push_back(resultListener);
700
701        // Add the results dispatcher callback
702        resultsDispatcherClass->needed = true;
703        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
704                new LiteralExpression(format_int(index)), resultListener);
705    } else {
706        resultParameter = NULL_VALUE;
707    }
708
709    // All proxy methods take an error parameter
710    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
711    proxyMethod->parameters.push_back(errorListener);
712
713    // Call the broker
714    proxyMethod->statements->Add(new MethodCall(RPC_BROKER_TYPE, "sendRequest", 6,
715                new FieldVariable(THIS_VALUE, "_context"),
716                new StringLiteralExpression(method->name.data),
717                proxyClass->endpoint,
718                new MethodCall(_data, "serialize"),
719                resultParameter,
720                errorListener));
721}
722
723static void
724generate_result_dispatcher_method(const method_type* method,
725        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
726{
727    arg_type* arg;
728    Method* dispatchMethod;
729    Variable* dispatchParam;
730    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
731
732    Variable* classLoader = NULL;
733    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
734    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
735                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
736
737    // The callback method itself
738    MethodCall* realCall = new MethodCall(
739            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
740            results_method_name(method->name.data));
741
742    // The return value
743    {
744        Type* t = NAMES.Search(method->type.type.data);
745        Variable* rv = new Variable(t, "rv");
746        dispatchMethod->statements->Add(new VariableDeclaration(rv));
747        generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
748                resultData, &classLoader);
749        realCall->arguments.push_back(rv);
750    }
751
752    VariableFactory stubArgs("arg");
753    arg = method->args;
754    while (arg != NULL) {
755        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
756            // Unmarshall the results
757            Type* t = NAMES.Search(arg->type.type.data);
758            Variable* v = stubArgs.Get(t);
759            dispatchMethod->statements->Add(new VariableDeclaration(v));
760
761            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
762                    resultData, &classLoader);
763
764            // Add the argument to the callback
765            realCall->arguments.push_back(v);
766        }
767        arg = arg->next;
768    }
769
770    // Call the callback method
771    dispatchMethod->statements->Add(realCall);
772}
773
774static void
775generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
776        ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
777        int index)
778{
779    arg_type* arg;
780
781    // == the callback interface for results ================================
782    // the service base class
783    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
784
785    // == the method in the proxy class =====================================
786    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
787
788    // == the method in the result dispatcher class =========================
789    if (resultsInterfaceType != NULL) {
790        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
791                index);
792    }
793
794    // == The abstract method that the service developers implement ==========
795    Method* decl = new Method;
796        decl->comment = gather_comments(method->comments_token->extra);
797        decl->modifiers = PUBLIC | ABSTRACT;
798        decl->returnType = NAMES.Search(method->type.type.data);
799        decl->returnTypeDimension = method->type.dimension;
800        decl->name = method->name.data;
801    arg = method->args;
802    while (arg != NULL) {
803        decl->parameters.push_back(new Variable(
804                            NAMES.Search(arg->type.type.data), arg->name.data,
805                            arg->type.dimension));
806        arg = arg->next;
807    }
808
809    // Add the default RpcContext param to all methods
810    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
811
812    serviceBaseClass->elements.push_back(decl);
813
814
815    // == the dispatch method in the service base class ======================
816    serviceBaseClass->AddMethod(method);
817}
818
819static void
820generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
821        ServiceBaseClass* serviceBaseClass, ListenerClass* listenerClass,
822        PresenterClass* presenterClass, int index)
823{
824    arg_type* arg;
825    listenerClass->needed = true;
826
827    // == the push method in the service base class =========================
828    Method* push = new Method;
829        push->modifiers = PUBLIC;
830        push->name = push_method_name(method->name.data);
831        push->statements = new StatementBlock;
832        push->returnType = VOID_TYPE;
833    serviceBaseClass->elements.push_back(push);
834
835    // The local variables
836    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
837    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
838
839    // Add the arguments
840    arg = method->args;
841    while (arg != NULL) {
842        // Function signature
843        Type* t = NAMES.Search(arg->type.type.data);
844        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
845        push->parameters.push_back(v);
846
847        // Input parameter marshalling
848        generate_write_to_data(t, push->statements,
849                new StringLiteralExpression(arg->name.data), v, _data);
850
851        arg = arg->next;
852    }
853
854    // Send the notifications
855    push->statements->Add(new MethodCall("pushEvent", 2,
856                new StringLiteralExpression(method->name.data),
857                new MethodCall(_data, "serialize")));
858
859    // == the event callback dispatcher method  ====================================
860    presenterClass->AddMethod(method);
861
862    // == the event method in the listener base class =====================
863    Method* event = new Method;
864        event->modifiers = PUBLIC;
865        event->name = method->name.data;
866        event->statements = new StatementBlock;
867        event->returnType = VOID_TYPE;
868    listenerClass->elements.push_back(event);
869    arg = method->args;
870    while (arg != NULL) {
871        event->parameters.push_back(new Variable(
872                            NAMES.Search(arg->type.type.data), arg->name.data,
873                            arg->type.dimension));
874        arg = arg->next;
875    }
876
877    // Add a final parameter: RpcContext. Contains data about
878    // incoming request (e.g., certificate)
879    event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
880}
881
882static void
883generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
884{
885    // AndroidAtHomePresenter _presenter;
886    // void registerListener(Listener listener) {
887    //     unregisterListener();
888    //     _presenter = new Presenter(_context, _endpoint, listener);
889    //     _presenter.attachToModel();
890    // }
891    // void unregisterListener() {
892    //     if (_presenter != null) {
893    //         _presenter.detachFromModel();
894    //     }
895    // }
896
897    Variable* _presenter = new Variable(presenterType, "_presenter");
898    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
899
900    Variable* listener = new Variable(listenerType, "listener");
901
902    Method* registerMethod = new Method;
903        registerMethod->modifiers = PUBLIC;
904        registerMethod->returnType = VOID_TYPE;
905        registerMethod->name = "registerListener";
906        registerMethod->statements = new StatementBlock;
907        registerMethod->parameters.push_back(listener);
908    proxyClass->elements.push_back(registerMethod);
909
910    registerMethod->statements->Add(new MethodCall(THIS_VALUE, "unregisterListener"));
911    registerMethod->statements->Add(new Assignment(_presenter, new NewExpression(presenterType,
912                    3, proxyClass->context, proxyClass->endpoint, listener)));
913    registerMethod->statements->Add(new MethodCall(_presenter, "attachToModel"));
914
915    Method* unregisterMethod = new Method;
916        unregisterMethod->modifiers = PUBLIC;
917        unregisterMethod->returnType = VOID_TYPE;
918        unregisterMethod->name = "unregisterListener";
919        unregisterMethod->statements = new StatementBlock;
920    proxyClass->elements.push_back(unregisterMethod);
921
922    IfStatement* ifst = new IfStatement;
923        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
924    unregisterMethod->statements->Add(ifst);
925
926    ifst->statements->Add(new MethodCall(_presenter, "detachFromModel"));
927    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
928}
929
930Class*
931generate_rpc_interface_class(const interface_type* iface)
932{
933    // the proxy class
934    InterfaceType* interfaceType = static_cast<InterfaceType*>(
935        NAMES.Find(iface->package, iface->name.data));
936    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
937
938    // the listener class
939    ListenerClass* listener = new ListenerClass(iface);
940
941    // the presenter class
942    PresenterClass* presenter = new PresenterClass(iface, listener->type);
943
944    // the service base class
945    ServiceBaseClass* base = new ServiceBaseClass(iface);
946    proxy->elements.push_back(base);
947
948    // the result dispatcher
949    ResultDispatcherClass* results = new ResultDispatcherClass();
950
951    // all the declared methods of the proxy
952    int index = 0;
953    interface_item_type* item = iface->interface_items;
954    while (item != NULL) {
955        if (item->item_type == METHOD_TYPE) {
956            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
957                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
958            } else {
959                generate_regular_method((method_type*)item, proxy, base, results, index);
960            }
961        }
962        item = item->next;
963        index++;
964    }
965    presenter->DoneWithMethods();
966    base->DoneWithMethods();
967
968    // only add this if there are methods with results / out parameters
969    if (results->needed) {
970        proxy->elements.push_back(results);
971    }
972    if (listener->needed) {
973        proxy->elements.push_back(listener);
974        proxy->elements.push_back(presenter);
975        generate_listener_methods(proxy, presenter->type, listener->type);
976    }
977
978    return proxy;
979}
980