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