generate_java_rpc.cpp revision e24dbeafe64278408b3342fcb77756bc7d091791
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
355    // methods
356    generate_ctor();
357}
358
359PresenterClass::~PresenterClass()
360{
361}
362
363void
364PresenterClass::generate_ctor()
365{
366    Variable* context = new Variable(CONTEXT_TYPE, "context");
367    Variable* endpoint = new Variable(RPC_SERVICE_INFO_TYPE, "endpoint");
368    Variable* listener = new Variable(this->_listener->type, "listener");
369    Method* ctor = new Method;
370        ctor->modifiers = PUBLIC;
371        ctor->name = class_name_leaf(this->type->Name());
372        ctor->statements = new StatementBlock;
373        ctor->parameters.push_back(context);
374        ctor->parameters.push_back(endpoint);
375        ctor->parameters.push_back(listener);
376    this->elements.push_back(ctor);
377
378    ctor->statements->Add(new MethodCall("super", 3, context, endpoint, listener));
379    ctor->statements->Add(new Assignment(this->_listener, listener));
380}
381
382// =================================================
383class ListenerClass : public Class
384{
385public:
386    ListenerClass(const interface_type* iface);
387    virtual ~ListenerClass();
388
389    bool needed;
390
391private:
392    void generate_ctor();
393};
394
395ListenerClass::ListenerClass(const interface_type* iface)
396    :Class(),
397     needed(false)
398{
399    this->comment = "/** Extend this to listen to the events from this class. */";
400    this->modifiers = STATIC | PUBLIC ;
401    this->what = Class::CLASS;
402    this->type = new Type(iface->package ? iface->package : "",
403                        append(iface->name.data, ".Listener"),
404                        Type::GENERATED, false, false, false);
405    this->extends = PRESENTER_LISTENER_BASE_TYPE;
406}
407
408ListenerClass::~ListenerClass()
409{
410}
411
412// =================================================
413class ServiceBaseClass : public DispatcherClass
414{
415public:
416    ServiceBaseClass(const interface_type* iface);
417    virtual ~ServiceBaseClass();
418
419    bool needed;
420
421private:
422    void generate_ctor();
423};
424
425ServiceBaseClass::ServiceBaseClass(const interface_type* iface)
426    :DispatcherClass(iface, THIS_VALUE),
427     needed(false)
428{
429    this->comment = "/** Extend this to implement a link service. */";
430    this->modifiers = STATIC | PUBLIC | ABSTRACT;
431    this->what = Class::CLASS;
432    this->type = new Type(iface->package ? iface->package : "",
433                        append(iface->name.data, ".ServiceBase"),
434                        Type::GENERATED, false, false, false);
435    this->extends = RPC_SERVICE_BASE_TYPE;
436
437    // methods
438    generate_ctor();
439}
440
441ServiceBaseClass::~ServiceBaseClass()
442{
443}
444
445void
446ServiceBaseClass::generate_ctor()
447{
448    Variable* container = new Variable(SERVICE_CONTAINER_TYPE, "container");
449    Variable* name = new Variable(STRING_TYPE, "name");
450    Variable* type = new Variable(STRING_TYPE, "type");
451    Variable* version = new Variable(INT_TYPE, "version");
452    Method* ctor = new Method;
453        ctor->modifiers = PUBLIC;
454        ctor->name = class_name_leaf(this->type->Name());
455        ctor->statements = new StatementBlock;
456        ctor->parameters.push_back(container);
457        ctor->parameters.push_back(name);
458        ctor->parameters.push_back(type);
459        ctor->parameters.push_back(version);
460    this->elements.push_back(ctor);
461
462    ctor->statements->Add(new MethodCall("super", 4, container, name, type, version));
463}
464
465// =================================================
466class ResultDispatcherClass : public Class
467{
468public:
469    ResultDispatcherClass();
470    virtual ~ResultDispatcherClass();
471
472    void AddMethod(int index, const string& name, Method** method, Variable** param);
473
474    bool needed;
475    Variable* methodId;
476    Variable* callback;
477    Method* onResultMethod;
478    Variable* resultParam;
479    SwitchStatement* methodSwitch;
480
481private:
482    void generate_ctor();
483    void generate_onResult();
484};
485
486ResultDispatcherClass::ResultDispatcherClass()
487    :Class(),
488     needed(false)
489{
490    this->modifiers = PRIVATE | FINAL;
491    this->what = Class::CLASS;
492    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
493    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
494
495    // methodId
496    this->methodId = new Variable(INT_TYPE, "methodId");
497    this->elements.push_back(new Field(PRIVATE, this->methodId));
498    this->callback = new Variable(OBJECT_TYPE, "callback");
499    this->elements.push_back(new Field(PRIVATE, this->callback));
500
501    // methods
502    generate_ctor();
503    generate_onResult();
504}
505
506ResultDispatcherClass::~ResultDispatcherClass()
507{
508}
509
510void
511ResultDispatcherClass::generate_ctor()
512{
513    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
514    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
515    Method* ctor = new Method;
516        ctor->modifiers = PUBLIC;
517        ctor->name = class_name_leaf(this->type->Name());
518        ctor->statements = new StatementBlock;
519        ctor->parameters.push_back(methodIdParam);
520        ctor->parameters.push_back(callbackParam);
521    this->elements.push_back(ctor);
522
523    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
524    ctor->statements->Add(new Assignment(this->callback, callbackParam));
525}
526
527void
528ResultDispatcherClass::generate_onResult()
529{
530    this->onResultMethod = new Method;
531        this->onResultMethod->modifiers = PUBLIC;
532        this->onResultMethod->returnType = VOID_TYPE;
533        this->onResultMethod->returnTypeDimension = 0;
534        this->onResultMethod->name = "onResult";
535        this->onResultMethod->statements = new StatementBlock;
536    this->elements.push_back(this->onResultMethod);
537
538    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
539    this->onResultMethod->parameters.push_back(this->resultParam);
540
541    this->methodSwitch = new SwitchStatement(this->methodId);
542    this->onResultMethod->statements->Add(this->methodSwitch);
543}
544
545void
546ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
547{
548    Method* m = new Method;
549        m->modifiers = PUBLIC;
550        m->returnType = VOID_TYPE;
551        m->returnTypeDimension = 0;
552        m->name = name;
553        m->statements = new StatementBlock;
554    *param = new Variable(BYTE_TYPE, "result", 1);
555    m->parameters.push_back(*param);
556    this->elements.push_back(m);
557    *method = m;
558
559    Case* c = new Case(format_int(index));
560    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
561    c->statements->Add(new Break());
562
563    this->methodSwitch->cases.push_back(c);
564}
565
566// =================================================
567static void
568generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
569{
570    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
571    exit(1);
572}
573
574static void
575generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
576                            Variable* data, Variable** cl)
577{
578    Expression* k = new StringLiteralExpression(key);
579    if (v->dimension == 0) {
580        t->CreateFromRpcData(addTo, k, v, data, cl);
581    }
582    if (v->dimension == 1) {
583        //t->ReadArrayFromRpcData(addTo, v, data, cl);
584        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
585                __FILE__, __LINE__);
586    }
587}
588
589static void
590generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
591{
592    if (v->dimension == 0) {
593        t->WriteToRpcData(addTo, k, v, data, 0);
594    }
595    if (v->dimension == 1) {
596        //t->WriteArrayToParcel(addTo, v, data);
597        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
598                __FILE__, __LINE__);
599    }
600}
601
602// =================================================
603static Type*
604generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
605{
606    arg_type* arg;
607
608    string resultsMethodName = results_method_name(method->name.data);
609    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
610            Type::GENERATED, false, false, false);
611
612    if (!method->oneway) {
613        Class* resultsClass = new Class;
614            resultsClass->modifiers = STATIC | PUBLIC;
615            resultsClass->what = Class::INTERFACE;
616            resultsClass->type = resultsInterfaceType;
617
618        Method* resultMethod = new Method;
619            resultMethod->comment = gather_comments(method->comments_token->extra);
620            resultMethod->modifiers = PUBLIC;
621            resultMethod->returnType = VOID_TYPE;
622            resultMethod->returnTypeDimension = 0;
623            resultMethod->name = resultsMethodName;
624        if (0 != strcmp("void", method->type.type.data)) {
625            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
626                        "_result", method->type.dimension));
627        }
628        arg = method->args;
629        while (arg != NULL) {
630            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
631                resultMethod->parameters.push_back(new Variable(
632                                    NAMES.Search(arg->type.type.data), arg->name.data,
633                                    arg->type.dimension));
634            }
635            arg = arg->next;
636        }
637        resultsClass->elements.push_back(resultMethod);
638
639        if (resultMethod->parameters.size() > 0) {
640            proxyClass->elements.push_back(resultsClass);
641            return resultsInterfaceType;
642        }
643    }
644    //delete resultsInterfaceType;
645    return NULL;
646}
647
648static void
649generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
650        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
651{
652    arg_type* arg;
653    Method* proxyMethod = new Method;
654        proxyMethod->comment = gather_comments(method->comments_token->extra);
655        proxyMethod->modifiers = PUBLIC;
656        proxyMethod->returnType = VOID_TYPE;
657        proxyMethod->returnTypeDimension = 0;
658        proxyMethod->name = method->name.data;
659        proxyMethod->statements = new StatementBlock;
660    proxyClass->elements.push_back(proxyMethod);
661
662    // The local variables
663    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
664    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
665
666    // Add the arguments
667    arg = method->args;
668    while (arg != NULL) {
669        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
670            // Function signature
671            Type* t = NAMES.Search(arg->type.type.data);
672            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
673            proxyMethod->parameters.push_back(v);
674
675            // Input parameter marshalling
676            generate_write_to_data(t, proxyMethod->statements,
677                    new StringLiteralExpression(arg->name.data), v, _data);
678        }
679        arg = arg->next;
680    }
681
682    // If there is a results interface for this class
683    Expression* resultParameter;
684    if (resultsInterfaceType != NULL) {
685        // Result interface parameter
686        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
687        proxyMethod->parameters.push_back(resultListener);
688
689        // Add the results dispatcher callback
690        resultsDispatcherClass->needed = true;
691        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
692                new LiteralExpression(format_int(index)), resultListener);
693    } else {
694        resultParameter = NULL_VALUE;
695    }
696
697    // All proxy methods take an error parameter
698    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
699    proxyMethod->parameters.push_back(errorListener);
700
701    // Call the broker
702    proxyMethod->statements->Add(new MethodCall(RPC_BROKER_TYPE, "sendRequest", 6,
703                new FieldVariable(THIS_VALUE, "_context"),
704                new StringLiteralExpression(method->name.data),
705                proxyClass->endpoint,
706                new MethodCall(_data, "serialize"),
707                resultParameter,
708                errorListener));
709}
710
711static void
712generate_result_dispatcher_method(const method_type* method,
713        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
714{
715    arg_type* arg;
716    Method* dispatchMethod;
717    Variable* dispatchParam;
718    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
719
720    Variable* classLoader = NULL;
721    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
722    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
723                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
724
725    // The callback method itself
726    MethodCall* realCall = new MethodCall(
727            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
728            results_method_name(method->name.data));
729
730    // The return value
731    {
732        Type* t = NAMES.Search(method->type.type.data);
733        Variable* rv = new Variable(t, "rv");
734        dispatchMethod->statements->Add(new VariableDeclaration(rv));
735        generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
736                resultData, &classLoader);
737        realCall->arguments.push_back(rv);
738    }
739
740    VariableFactory stubArgs("arg");
741    arg = method->args;
742    while (arg != NULL) {
743        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
744            // Unmarshall the results
745            Type* t = NAMES.Search(arg->type.type.data);
746            Variable* v = stubArgs.Get(t);
747            dispatchMethod->statements->Add(new VariableDeclaration(v));
748
749            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
750                    resultData, &classLoader);
751
752            // Add the argument to the callback
753            realCall->arguments.push_back(v);
754        }
755        arg = arg->next;
756    }
757
758    // Call the callback method
759    dispatchMethod->statements->Add(realCall);
760}
761
762static void
763generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
764        ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
765        int index)
766{
767    arg_type* arg;
768
769    // == the callback interface for results ================================
770    // the service base class
771    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
772
773    // == the method in the proxy class =====================================
774    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
775
776    // == the method in the result dispatcher class =========================
777    if (resultsInterfaceType != NULL) {
778        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
779                index);
780    }
781
782    // == The abstract method that the service developers implement ==========
783    Method* decl = new Method;
784        decl->comment = gather_comments(method->comments_token->extra);
785        decl->modifiers = PUBLIC | ABSTRACT;
786        decl->returnType = NAMES.Search(method->type.type.data);
787        decl->returnTypeDimension = method->type.dimension;
788        decl->name = method->name.data;
789    arg = method->args;
790    while (arg != NULL) {
791        decl->parameters.push_back(new Variable(
792                            NAMES.Search(arg->type.type.data), arg->name.data,
793                            arg->type.dimension));
794        arg = arg->next;
795    }
796    serviceBaseClass->elements.push_back(decl);
797
798
799    // == the dispatch method in the service base class ======================
800    serviceBaseClass->AddMethod(method);
801}
802
803static void
804generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
805        ServiceBaseClass* serviceBaseClass, ListenerClass* listenerClass,
806        PresenterClass* presenterClass, int index)
807{
808    arg_type* arg;
809    listenerClass->needed = true;
810
811    // == the push method in the service base class =========================
812    Method* push = new Method;
813        push->modifiers = PUBLIC;
814        push->name = push_method_name(method->name.data);
815        push->statements = new StatementBlock;
816        push->returnType = VOID_TYPE;
817    serviceBaseClass->elements.push_back(push);
818
819    // The local variables
820    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
821    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
822
823    // Add the arguments
824    arg = method->args;
825    while (arg != NULL) {
826        // Function signature
827        Type* t = NAMES.Search(arg->type.type.data);
828        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
829        push->parameters.push_back(v);
830
831        // Input parameter marshalling
832        generate_write_to_data(t, push->statements,
833                new StringLiteralExpression(arg->name.data), v, _data);
834
835        arg = arg->next;
836    }
837
838    // Send the notifications
839    push->statements->Add(new MethodCall("pushEvent", 2,
840                new StringLiteralExpression(method->name.data),
841                new MethodCall(_data, "serialize")));
842
843    // == the event callback dispatcher method  ====================================
844    presenterClass->AddMethod(method);
845
846    // == the event method in the listener base class =====================
847    Method* event = new Method;
848        event->modifiers = PUBLIC;
849        event->name = method->name.data;
850        event->statements = new StatementBlock;
851        event->returnType = VOID_TYPE;
852    listenerClass->elements.push_back(event);
853    arg = method->args;
854    while (arg != NULL) {
855        event->parameters.push_back(new Variable(
856                            NAMES.Search(arg->type.type.data), arg->name.data,
857                            arg->type.dimension));
858        arg = arg->next;
859    }
860}
861
862static void
863generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
864{
865    // AndroidAtHomePresenter _presenter;
866    // void registerListener(Listener listener) {
867    //     unregisterListener();
868    //     _presenter = new Presenter(_context, _endpoint, listener);
869    //     _presenter.attachToModel();
870    // }
871    // void unregisterListener() {
872    //     if (_presenter != null) {
873    //         _presenter.detachFromModel();
874    //     }
875    // }
876
877    Variable* _presenter = new Variable(presenterType, "_presenter");
878    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
879
880    Variable* listener = new Variable(listenerType, "listener");
881
882    Method* registerMethod = new Method;
883        registerMethod->modifiers = PUBLIC;
884        registerMethod->returnType = VOID_TYPE;
885        registerMethod->name = "registerListener";
886        registerMethod->statements = new StatementBlock;
887        registerMethod->parameters.push_back(listener);
888    proxyClass->elements.push_back(registerMethod);
889
890    registerMethod->statements->Add(new MethodCall(THIS_VALUE, "unregisterListener"));
891    registerMethod->statements->Add(new Assignment(_presenter, new NewExpression(presenterType,
892                    3, proxyClass->context, proxyClass->endpoint, listener)));
893    registerMethod->statements->Add(new MethodCall(_presenter, "attachToModel"));
894
895    Method* unregisterMethod = new Method;
896        unregisterMethod->modifiers = PUBLIC;
897        unregisterMethod->returnType = VOID_TYPE;
898        unregisterMethod->name = "unregisterListener";
899        unregisterMethod->statements = new StatementBlock;
900    proxyClass->elements.push_back(unregisterMethod);
901
902    IfStatement* ifst = new IfStatement;
903        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
904    unregisterMethod->statements->Add(ifst);
905
906    ifst->statements->Add(new MethodCall(_presenter, "detachFromModel"));
907    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
908}
909
910Class*
911generate_rpc_interface_class(const interface_type* iface)
912{
913    // the proxy class
914    InterfaceType* interfaceType = static_cast<InterfaceType*>(
915        NAMES.Find(iface->package, iface->name.data));
916    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
917
918    // the listener class
919    ListenerClass* listener = new ListenerClass(iface);
920
921    // the presenter class
922    PresenterClass* presenter = new PresenterClass(iface, listener->type);
923
924    // the service base class
925    ServiceBaseClass* base = new ServiceBaseClass(iface);
926    proxy->elements.push_back(base);
927
928    // the result dispatcher
929    ResultDispatcherClass* results = new ResultDispatcherClass();
930
931    // all the declared methods of the proxy
932    int index = 0;
933    interface_item_type* item = iface->interface_items;
934    while (item != NULL) {
935        if (item->item_type == METHOD_TYPE) {
936            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
937                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
938            } else {
939                generate_regular_method((method_type*)item, proxy, base, results, index);
940            }
941        }
942        item = item->next;
943        index++;
944    }
945    presenter->DoneWithMethods();
946    base->DoneWithMethods();
947
948    // only add this if there are methods with results / out parameters
949    if (results->needed) {
950        proxy->elements.push_back(results);
951    }
952    if (listener->needed) {
953        proxy->elements.push_back(listener);
954        proxy->elements.push_back(presenter);
955        generate_listener_methods(proxy, presenter->type, listener->type);
956    }
957
958    return proxy;
959}
960
961