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