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