generate_java_rpc.cpp revision 0ca2a36d8dd783e7ba5abffd5929c0e33c6ba91d
1#include "generate_java.h"
2#include "Type.h"
3#include <string.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8Type* SERVICE_CONTAINER_TYPE = new Type("com.android.athome.service",
9        "AndroidAtHomeServiceContainer", Type::BUILT_IN, false, false, false);
10
11static string
12format_int(int n)
13{
14    char str[20];
15    sprintf(str, "%d", n);
16    return string(str);
17}
18
19static string
20class_name_leaf(const string& str)
21{
22    string::size_type pos = str.rfind('.');
23    if (pos == string::npos) {
24        return str;
25    } else {
26        return string(str, pos+1);
27    }
28}
29
30// =================================================
31class RpcProxyClass : public Class
32{
33public:
34    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
35    virtual ~RpcProxyClass();
36
37    Variable* endpoint;
38    Variable* context;
39
40private:
41    void generate_ctor();
42};
43
44RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
45    :Class()
46{
47    this->comment = gather_comments(iface->comments_token->extra);
48    this->modifiers = PUBLIC;
49    this->what = Class::CLASS;
50    this->type = interfaceType;
51
52    // context
53    this->context = new Variable(CONTEXT_TYPE, "_context");
54    this->elements.push_back(new Field(PRIVATE, this->context));
55    // endpoint
56    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
57    this->elements.push_back(new Field(PRIVATE, this->endpoint));
58
59    // methods
60    generate_ctor();
61}
62
63RpcProxyClass::~RpcProxyClass()
64{
65}
66
67void
68RpcProxyClass::generate_ctor()
69{
70    Variable* context = new Variable(CONTEXT_TYPE, "context");
71    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
72    Method* ctor = new Method;
73        ctor->modifiers = PUBLIC;
74        ctor->name = this->type->Name();
75        ctor->statements = new StatementBlock;
76        ctor->parameters.push_back(context);
77        ctor->parameters.push_back(endpoint);
78    this->elements.push_back(ctor);
79
80    ctor->statements->Add(new Assignment(this->context, context));
81    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
82}
83
84// =================================================
85class ServiceBaseClass : public Class
86{
87public:
88    ServiceBaseClass(const interface_type* iface);
89    virtual ~ServiceBaseClass();
90
91    void AddMethod(const string& methodName, StatementBlock** statements);
92    void DoneWithMethods();
93
94    bool needed;
95    Method* processMethod;
96    Variable* actionParam;
97    Variable* requestParam;
98    Variable* errorParam;
99    Variable* requestData;
100    Variable* resultData;
101    IfStatement* dispatchIfStatement;
102
103private:
104    void generate_ctor();
105    void generate_process();
106};
107
108ServiceBaseClass::ServiceBaseClass(const interface_type* iface)
109    :Class(),
110     needed(false),
111     dispatchIfStatement(NULL)
112{
113    this->comment = "/** Extend this to implement a link service. */";
114    this->modifiers = STATIC | PUBLIC | ABSTRACT;
115    this->what = Class::CLASS;
116    this->type = NAMES.Find(iface->package, append(iface->name.data, ".ServiceBase").c_str());
117    this->extends = RPC_SERVICE_BASE_TYPE;
118
119    // methods
120    generate_ctor();
121    generate_process();
122}
123
124ServiceBaseClass::~ServiceBaseClass()
125{
126}
127
128void
129ServiceBaseClass::generate_ctor()
130{
131    Variable* container = new Variable(SERVICE_CONTAINER_TYPE, "container");
132    Variable* name = new Variable(STRING_TYPE, "name");
133    Variable* type = new Variable(STRING_TYPE, "type");
134    Variable* version = new Variable(INT_TYPE, "version");
135    Method* ctor = new Method;
136        ctor->modifiers = PUBLIC;
137        ctor->name = class_name_leaf(this->type->Name());
138        ctor->statements = new StatementBlock;
139        ctor->parameters.push_back(container);
140        ctor->parameters.push_back(name);
141        ctor->parameters.push_back(type);
142        ctor->parameters.push_back(version);
143    this->elements.push_back(ctor);
144
145    ctor->statements->Add(new MethodCall("super", 4, container, name, type, version));
146}
147
148void
149ServiceBaseClass::generate_process()
150{
151    // byte[] process(String action, byte[] params, RpcError status)
152    this->processMethod = new Method;
153        this->processMethod->modifiers = PUBLIC;
154        this->processMethod->returnType = BYTE_TYPE;
155        this->processMethod->returnTypeDimension = 1;
156        this->processMethod->name = "process";
157        this->processMethod->statements = new StatementBlock;
158    this->elements.push_back(this->processMethod);
159
160    this->actionParam = new Variable(STRING_TYPE, "action");
161    this->processMethod->parameters.push_back(this->actionParam);
162
163    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
164    this->processMethod->parameters.push_back(this->requestParam);
165
166    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
167    this->processMethod->parameters.push_back(this->errorParam);
168
169    this->requestData = new Variable(RPC_DATA_TYPE, "request");
170    this->processMethod->statements->Add(new VariableDeclaration(requestData,
171                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
172
173    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
174    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
175                NULL_VALUE));
176}
177
178void
179ServiceBaseClass::AddMethod(const string& methodName, StatementBlock** statements)
180{
181    IfStatement* ifs = new IfStatement();
182        ifs->expression = new MethodCall(new StringLiteralExpression(methodName), "equals", 1,
183                this->actionParam);
184        ifs->statements = *statements = new StatementBlock;
185    if (this->dispatchIfStatement == NULL) {
186        this->dispatchIfStatement = ifs;
187        this->processMethod->statements->Add(dispatchIfStatement);
188    } else {
189        this->dispatchIfStatement->elseif = ifs;
190        this->dispatchIfStatement = ifs;
191    }
192}
193
194void
195ServiceBaseClass::DoneWithMethods()
196{
197    IfStatement* fallthrough = new IfStatement();
198        fallthrough->statements = new StatementBlock;
199        fallthrough->statements->Add(new ReturnStatement(
200                    new MethodCall(SUPER_VALUE, "process", 3, this->actionParam, this->requestParam,
201                        this->errorParam)));
202    this->dispatchIfStatement->elseif = fallthrough;
203    IfStatement* s = new IfStatement;
204        s->statements = new StatementBlock;
205    this->processMethod->statements->Add(s);
206    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
207    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
208    s->elseif = new IfStatement;
209    s = s->elseif;
210    s->statements->Add(new ReturnStatement(NULL_VALUE));
211}
212
213// =================================================
214class ResultDispatcherClass : public Class
215{
216public:
217    ResultDispatcherClass();
218    virtual ~ResultDispatcherClass();
219
220    void AddMethod(int index, const string& name, Method** method, Variable** param);
221
222    bool needed;
223    Variable* methodId;
224    Variable* callback;
225    Method* onResultMethod;
226    Variable* resultParam;
227    SwitchStatement* methodSwitch;
228
229private:
230    void generate_ctor();
231    void generate_onResult();
232};
233
234ResultDispatcherClass::ResultDispatcherClass()
235    :Class(),
236     needed(false)
237{
238    this->modifiers = PRIVATE | FINAL;
239    this->what = Class::CLASS;
240    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
241    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
242
243    // methodId
244    this->methodId = new Variable(INT_TYPE, "methodId");
245    this->elements.push_back(new Field(PRIVATE, this->methodId));
246    this->callback = new Variable(OBJECT_TYPE, "callback");
247    this->elements.push_back(new Field(PRIVATE, this->callback));
248
249    // methods
250    generate_ctor();
251    generate_onResult();
252}
253
254ResultDispatcherClass::~ResultDispatcherClass()
255{
256}
257
258void
259ResultDispatcherClass::generate_ctor()
260{
261    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
262    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
263    Method* ctor = new Method;
264        ctor->modifiers = PUBLIC;
265        ctor->name = this->type->Name();
266        ctor->statements = new StatementBlock;
267        ctor->parameters.push_back(methodIdParam);
268        ctor->parameters.push_back(callbackParam);
269    this->elements.push_back(ctor);
270
271    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
272    ctor->statements->Add(new Assignment(this->callback, callbackParam));
273}
274
275void
276ResultDispatcherClass::generate_onResult()
277{
278    this->onResultMethod = new Method;
279        this->onResultMethod->modifiers = PUBLIC;
280        this->onResultMethod->returnType = VOID_TYPE;
281        this->onResultMethod->returnTypeDimension = 0;
282        this->onResultMethod->name = "onResult";
283        this->onResultMethod->statements = new StatementBlock;
284    this->elements.push_back(this->onResultMethod);
285
286    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
287    this->onResultMethod->parameters.push_back(this->resultParam);
288
289    this->methodSwitch = new SwitchStatement(this->methodId);
290    this->onResultMethod->statements->Add(this->methodSwitch);
291}
292
293void
294ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
295{
296    Method* m = new Method;
297        m->modifiers = PUBLIC;
298        m->returnType = VOID_TYPE;
299        m->returnTypeDimension = 0;
300        m->name = name;
301        m->statements = new StatementBlock;
302    *param = new Variable(BYTE_TYPE, "result", 1);
303    m->parameters.push_back(*param);
304    this->elements.push_back(m);
305    *method = m;
306
307    Case* c = new Case(format_int(index));
308    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
309    c->statements->Add(new Break());
310
311    this->methodSwitch->cases.push_back(c);
312}
313
314// =================================================
315static void
316generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
317{
318    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
319    exit(1);
320}
321
322static void
323generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
324                            Variable* data, Variable** cl)
325{
326    Expression* k = new StringLiteralExpression(key);
327    if (v->dimension == 0) {
328        t->CreateFromRpcData(addTo, k, v, data, cl);
329    }
330    if (v->dimension == 1) {
331        //t->ReadArrayFromRpcData(addTo, v, data, cl);
332        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
333                __FILE__, __LINE__);
334    }
335}
336
337static void
338generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
339{
340    if (v->dimension == 0) {
341        t->WriteToRpcData(addTo, k, v, data, 0);
342    }
343    if (v->dimension == 1) {
344        //t->WriteArrayToParcel(addTo, v, data);
345        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
346                __FILE__, __LINE__);
347    }
348}
349
350// =================================================
351static string
352results_class_name(const string& n)
353{
354    string str = n;
355    str[0] = toupper(str[0]);
356    str.insert(0, "On");
357    return str;
358}
359
360static string
361results_method_name(const string& n)
362{
363    string str = n;
364    str[0] = toupper(str[0]);
365    str.insert(0, "on");
366    return str;
367}
368
369static Type*
370generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
371{
372    arg_type* arg;
373
374    string resultsMethodName = results_method_name(method->name.data);
375    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
376            Type::GENERATED, false, false, false);
377
378    if (!method->oneway) {
379        Class* resultsClass = new Class;
380            resultsClass->modifiers = STATIC | PUBLIC;
381            resultsClass->what = Class::INTERFACE;
382            resultsClass->type = resultsInterfaceType;
383
384        Method* resultMethod = new Method;
385            resultMethod->comment = gather_comments(method->comments_token->extra);
386            resultMethod->modifiers = PUBLIC;
387            resultMethod->returnType = VOID_TYPE;
388            resultMethod->returnTypeDimension = 0;
389            resultMethod->name = resultsMethodName;
390        if (0 != strcmp("void", method->type.type.data)) {
391            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
392                        "_result", method->type.dimension));
393        }
394        arg = method->args;
395        while (arg != NULL) {
396            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
397                resultMethod->parameters.push_back(new Variable(
398                                    NAMES.Search(arg->type.type.data), arg->name.data,
399                                    arg->type.dimension));
400            }
401            arg = arg->next;
402        }
403        resultsClass->elements.push_back(resultMethod);
404
405        if (resultMethod->parameters.size() > 0) {
406            proxyClass->elements.push_back(resultsClass);
407            return resultsInterfaceType;
408        }
409    }
410    //delete resultsInterfaceType;
411    return NULL;
412}
413
414static void
415generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
416        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
417{
418    arg_type* arg;
419    Method* proxyMethod = new Method;
420        proxyMethod->comment = gather_comments(method->comments_token->extra);
421        proxyMethod->modifiers = PUBLIC;
422        proxyMethod->returnType = VOID_TYPE;
423        proxyMethod->returnTypeDimension = 0;
424        proxyMethod->name = method->name.data;
425        proxyMethod->statements = new StatementBlock;
426    proxyClass->elements.push_back(proxyMethod);
427
428    // The local variables
429    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
430    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
431
432    // Add the arguments
433    arg = method->args;
434    while (arg != NULL) {
435        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
436            // Function signature
437            Type* t = NAMES.Search(arg->type.type.data);
438            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
439            proxyMethod->parameters.push_back(v);
440
441            // Input parameter marshalling
442            generate_write_to_data(t, proxyMethod->statements,
443                    new StringLiteralExpression(arg->name.data), v, _data);
444        }
445        arg = arg->next;
446    }
447
448    // If there is a results interface for this class
449    Expression* resultParameter;
450    if (resultsInterfaceType != NULL) {
451        // Result interface parameter
452        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
453        proxyMethod->parameters.push_back(resultListener);
454
455        // Add the results dispatcher callback
456        resultsDispatcherClass->needed = true;
457        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
458                new LiteralExpression(format_int(index)), resultListener);
459    } else {
460        resultParameter = NULL_VALUE;
461    }
462
463    // All proxy methods take an error parameter
464    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
465    proxyMethod->parameters.push_back(errorListener);
466
467    // Call the broker
468    proxyMethod->statements->Add(new MethodCall(RPC_BROKER_TYPE, "sendRequest", 6,
469                new FieldVariable(THIS_VALUE, "_context"),
470                new StringLiteralExpression(method->name.data),
471                proxyClass->endpoint,
472                new MethodCall(_data, "serialize"),
473                resultParameter,
474                errorListener));
475}
476
477static void
478generate_result_dispatcher_method(const method_type* method,
479        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
480{
481    arg_type* arg;
482    Method* dispatchMethod;
483    Variable* dispatchParam;
484    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
485
486    Variable* classLoader = NULL;
487    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
488    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
489                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
490
491    // The callback method itself
492    MethodCall* realCall = new MethodCall(
493            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
494            results_method_name(method->name.data));
495
496    // The return value
497    {
498        Type* t = NAMES.Search(method->type.type.data);
499        Variable* rv = new Variable(t, "rv");
500        dispatchMethod->statements->Add(new VariableDeclaration(rv));
501        generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
502                resultData, &classLoader);
503        realCall->arguments.push_back(rv);
504    }
505
506    VariableFactory stubArgs("arg");
507    arg = method->args;
508    while (arg != NULL) {
509        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
510            // Unmarshall the results
511            Type* t = NAMES.Search(arg->type.type.data);
512            Variable* v = stubArgs.Get(t);
513            dispatchMethod->statements->Add(new VariableDeclaration(v));
514
515            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
516                    resultData, &classLoader);
517
518            // Add the argument to the callback
519            realCall->arguments.push_back(v);
520        }
521        arg = arg->next;
522    }
523
524    // Call the callback method
525    dispatchMethod->statements->Add(realCall);
526}
527
528static void
529generate_service_base_methods(const method_type* method, ServiceBaseClass* serviceBaseClass)
530{
531    arg_type* arg;
532    StatementBlock* block;
533    serviceBaseClass->AddMethod(method->name.data, &block);
534
535    // The abstract method that the service developers implement
536    Method* decl = new Method;
537        decl->comment = gather_comments(method->comments_token->extra);
538        decl->modifiers = PUBLIC | ABSTRACT;
539        decl->returnType = NAMES.Search(method->type.type.data);
540        decl->returnTypeDimension = method->type.dimension;
541        decl->name = method->name.data;
542
543    arg = method->args;
544    while (arg != NULL) {
545        decl->parameters.push_back(new Variable(
546                            NAMES.Search(arg->type.type.data), arg->name.data,
547                            arg->type.dimension));
548        arg = arg->next;
549    }
550
551    serviceBaseClass->elements.push_back(decl);
552
553    // The call to decl (from above)
554    MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
555
556    // args
557    Variable* classLoader = NULL;
558    VariableFactory stubArgs("_arg");
559    arg = method->args;
560    while (arg != NULL) {
561        Type* t = NAMES.Search(arg->type.type.data);
562        Variable* v = stubArgs.Get(t);
563        v->dimension = arg->type.dimension;
564
565        // Unmarshall the parameter
566        block->Add(new VariableDeclaration(v));
567        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
568            generate_create_from_data(t, block, arg->name.data, v,
569                    serviceBaseClass->requestData, &classLoader);
570        } else {
571            if (arg->type.dimension == 0) {
572                block->Add(new Assignment(v, new NewExpression(v->type)));
573            }
574            else if (arg->type.dimension == 1) {
575                generate_new_array(v->type, block, v, serviceBaseClass->requestData);
576            }
577            else {
578                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
579                        __LINE__);
580            }
581        }
582
583        // Add that parameter to the method call
584        realCall->arguments.push_back(v);
585
586        arg = arg->next;
587    }
588
589    // the real call
590    bool first = true;
591    Variable* _result = NULL;
592    if (0 == strcmp(method->type.type.data, "void")) {
593        block->Add(realCall);
594    } else {
595        _result = new Variable(decl->returnType, "_result",
596                                decl->returnTypeDimension);
597        block->Add(new VariableDeclaration(_result, realCall));
598
599        // need the result RpcData
600        if (first) {
601            block->Add(new Assignment(serviceBaseClass->resultData,
602                        new NewExpression(RPC_DATA_TYPE)));
603            first = false;
604        }
605
606        // marshall the return value
607        generate_write_to_data(decl->returnType, block,
608                new StringLiteralExpression("_result"), _result, serviceBaseClass->resultData);
609    }
610
611    // out parameters
612    int i = 0;
613    arg = method->args;
614    while (arg != NULL) {
615        Type* t = NAMES.Search(arg->type.type.data);
616        Variable* v = stubArgs.Get(i++);
617
618        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
619            // need the result RpcData
620            if (first) {
621                block->Add(new Assignment(serviceBaseClass->resultData,
622                            new NewExpression(RPC_DATA_TYPE)));
623                first = false;
624            }
625
626
627            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
628                    v, serviceBaseClass->resultData);
629        }
630
631        arg = arg->next;
632    }
633}
634
635static void
636generate_method(const method_type* method, RpcProxyClass* proxyClass,
637        ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
638        int index)
639{
640    // == the callback interface for results =================================
641    // the service base class
642    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
643
644    // == the method in the proxy class =====================================
645    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
646
647    // == the method in the result dispatcher class =========================
648    if (resultsInterfaceType != NULL) {
649        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
650                index);
651    }
652
653    // == the dispatch method in the service base class ======================
654    generate_service_base_methods(method, serviceBaseClass);
655}
656
657Class*
658generate_rpc_interface_class(const interface_type* iface)
659{
660    // the proxy class
661    InterfaceType* interfaceType = static_cast<InterfaceType*>(
662        NAMES.Find(iface->package, iface->name.data));
663    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
664
665    // the service base class
666    ServiceBaseClass* base = new ServiceBaseClass(iface);
667    proxy->elements.push_back(base);
668
669    // the result dispatcher
670    ResultDispatcherClass* results = new ResultDispatcherClass();
671
672    // all the declared methods of the proxy
673    int index = 0;
674    interface_item_type* item = iface->interface_items;
675    while (item != NULL) {
676        if (item->item_type == METHOD_TYPE) {
677            generate_method((method_type*)item, proxy, base, results, index);
678        }
679        item = item->next;
680        index++;
681    }
682    base->DoneWithMethods();
683
684    // only add this if there are methods with results / out parameters
685    if (results->needed) {
686        proxy->elements.push_back(results);
687    }
688
689    return proxy;
690}
691
692