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