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