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