blob: 456a950e20d09e21bb9300a71ababdc444fa6d3d [file] [log] [blame]
Joe Onoratoc596cfe2011-08-30 17:24:17 -07001#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
Joe Onorato3d0e06f2011-09-02 15:28:36 -0700172 this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700173 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));
Joe Onorato3d0e06f2011-09-02 15:28:36 -0700302 c->statements->Add(new Break());
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700303
304 this->methodSwitch->cases.push_back(c);
305}
306
307// =================================================
308static void
309generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
310{
311 fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
312 exit(1);
313}
314
315static void
316generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
317 Variable* data, Variable** cl)
318{
319 Expression* k = new StringLiteralExpression(key);
320 if (v->dimension == 0) {
321 t->CreateFromRpcData(addTo, k, v, data, cl);
322 }
323 if (v->dimension == 1) {
324 //t->ReadArrayFromRpcData(addTo, v, data, cl);
325 fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
326 __FILE__, __LINE__);
327 }
328}
329
330static void
331generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
332{
333 if (v->dimension == 0) {
334 t->WriteToRpcData(addTo, k, v, data, 0);
335 }
336 if (v->dimension == 1) {
337 //t->WriteArrayToParcel(addTo, v, data);
338 fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
339 __FILE__, __LINE__);
340 }
341}
342
343// =================================================
344static string
345results_class_name(const string& n)
346{
347 string str = n;
348 str[0] = toupper(str[0]);
349 str.insert(0, "On");
350 return str;
351}
352
353static string
354results_method_name(const string& n)
355{
356 string str = n;
357 str[0] = toupper(str[0]);
358 str.insert(0, "on");
359 return str;
360}
361
362static Type*
363generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
364{
365 arg_type* arg;
366
367 string resultsMethodName = results_method_name(method->name.data);
368 Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
369 Type::GENERATED, false, false);
370
371 if (!method->oneway) {
372 Class* resultsClass = new Class;
373 resultsClass->modifiers = STATIC | PUBLIC;
374 resultsClass->what = Class::INTERFACE;
375 resultsClass->type = resultsInterfaceType;
376
377 Method* resultMethod = new Method;
378 resultMethod->comment = gather_comments(method->comments_token->extra);
379 resultMethod->modifiers = PUBLIC;
380 resultMethod->returnType = VOID_TYPE;
381 resultMethod->returnTypeDimension = 0;
382 resultMethod->name = resultsMethodName;
383 if (0 != strcmp("void", method->type.type.data)) {
384 resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
385 "_result", method->type.dimension));
386 }
387 arg = method->args;
388 while (arg != NULL) {
389 if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
390 resultMethod->parameters.push_back(new Variable(
391 NAMES.Search(arg->type.type.data), arg->name.data,
392 arg->type.dimension));
393 }
394 arg = arg->next;
395 }
396 resultsClass->elements.push_back(resultMethod);
397
398 if (resultMethod->parameters.size() > 0) {
399 proxyClass->elements.push_back(resultsClass);
400 return resultsInterfaceType;
401 }
402 }
403 //delete resultsInterfaceType;
404 return NULL;
405}
406
407static void
408generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
409 ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
410{
411 arg_type* arg;
412 Method* proxyMethod = new Method;
413 proxyMethod->comment = gather_comments(method->comments_token->extra);
414 proxyMethod->modifiers = PUBLIC;
415 proxyMethod->returnType = VOID_TYPE;
416 proxyMethod->returnTypeDimension = 0;
417 proxyMethod->name = method->name.data;
418 proxyMethod->statements = new StatementBlock;
419 proxyClass->elements.push_back(proxyMethod);
420
421 // The local variables
422 Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
423 proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
424
425 // Add the arguments
426 arg = method->args;
427 while (arg != NULL) {
428 if (convert_direction(arg->direction.data) & IN_PARAMETER) {
429 // Function signature
430 Type* t = NAMES.Search(arg->type.type.data);
431 Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
432 proxyMethod->parameters.push_back(v);
433
434 // Input parameter marshalling
435 generate_write_to_data(t, proxyMethod->statements,
436 new StringLiteralExpression(arg->name.data), v, _data);
437 }
438 arg = arg->next;
439 }
440
441 // If there is a results interface for this class
442 Expression* resultParameter;
443 if (resultsInterfaceType != NULL) {
444 // Result interface parameter
445 Variable* resultListener = new Variable(resultsInterfaceType, "_result");
446 proxyMethod->parameters.push_back(resultListener);
447
448 // Add the results dispatcher callback
449 resultsDispatcherClass->needed = true;
450 resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
451 new LiteralExpression(format_int(index)), resultListener);
452 } else {
453 resultParameter = NULL_VALUE;
454 }
455
456 // All proxy methods take an error parameter
457 Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
458 proxyMethod->parameters.push_back(errorListener);
459
460 // Call the broker
461 proxyMethod->statements->Add(new MethodCall(RPC_BROKER_TYPE, "sendRequest", 6,
462 new FieldVariable(THIS_VALUE, "_context"),
463 new StringLiteralExpression(method->name.data),
464 proxyClass->endpoint,
465 new MethodCall(_data, "serialize"),
466 resultParameter,
467 errorListener));
468}
469
470static void
471generate_result_dispatcher_method(const method_type* method,
472 ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
473{
474 arg_type* arg;
475 Method* dispatchMethod;
476 Variable* dispatchParam;
477 resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
478
479 Variable* classLoader = NULL;
480 Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
481 dispatchMethod->statements->Add(new VariableDeclaration(resultData,
482 new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
483
484 // The callback method itself
485 MethodCall* realCall = new MethodCall(
486 new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
487 results_method_name(method->name.data));
488
489 // The return value
490 {
491 Type* t = NAMES.Search(method->type.type.data);
492 Variable* rv = new Variable(t, "rv");
493 dispatchMethod->statements->Add(new VariableDeclaration(rv));
494 generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
495 resultData, &classLoader);
496 realCall->arguments.push_back(rv);
497 }
498
499 VariableFactory stubArgs("arg");
500 arg = method->args;
501 while (arg != NULL) {
502 if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
503 // Unmarshall the results
504 Type* t = NAMES.Search(arg->type.type.data);
505 Variable* v = stubArgs.Get(t);
506 dispatchMethod->statements->Add(new VariableDeclaration(v));
507
508 generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
509 resultData, &classLoader);
510
511 // Add the argument to the callback
512 realCall->arguments.push_back(v);
513 }
514 arg = arg->next;
515 }
516
517 // Call the callback method
518 dispatchMethod->statements->Add(realCall);
519}
520
521static void
522generate_service_base_methods(const method_type* method, ServiceBaseClass* serviceBaseClass)
523{
524 arg_type* arg;
525 StatementBlock* block;
526 serviceBaseClass->AddMethod(method->name.data, &block);
527
528 // The abstract method that the service developers implement
529 Method* decl = new Method;
530 decl->comment = gather_comments(method->comments_token->extra);
531 decl->modifiers = PUBLIC | ABSTRACT;
532 decl->returnType = NAMES.Search(method->type.type.data);
533 decl->returnTypeDimension = method->type.dimension;
534 decl->name = method->name.data;
535
536 arg = method->args;
537 while (arg != NULL) {
538 decl->parameters.push_back(new Variable(
539 NAMES.Search(arg->type.type.data), arg->name.data,
540 arg->type.dimension));
541 arg = arg->next;
542 }
543
544 serviceBaseClass->elements.push_back(decl);
545
546 // The call to decl (from above)
547 MethodCall* realCall = new MethodCall(THIS_VALUE, method->name.data);
548
549 // args
550 Variable* classLoader = NULL;
551 VariableFactory stubArgs("_arg");
552 arg = method->args;
553 while (arg != NULL) {
554 Type* t = NAMES.Search(arg->type.type.data);
555 Variable* v = stubArgs.Get(t);
556 v->dimension = arg->type.dimension;
557
558 // Unmarshall the parameter
559 block->Add(new VariableDeclaration(v));
560 if (convert_direction(arg->direction.data) & IN_PARAMETER) {
561 generate_create_from_data(t, block, arg->name.data, v,
562 serviceBaseClass->requestData, &classLoader);
563 } else {
564 if (arg->type.dimension == 0) {
565 block->Add(new Assignment(v, new NewExpression(v->type)));
566 }
567 else if (arg->type.dimension == 1) {
568 generate_new_array(v->type, block, v, serviceBaseClass->requestData);
569 }
570 else {
571 fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
572 __LINE__);
573 }
574 }
575
576 // Add that parameter to the method call
577 realCall->arguments.push_back(v);
578
579 arg = arg->next;
580 }
581
582 // the real call
Joe Onorato3d0e06f2011-09-02 15:28:36 -0700583 bool first = true;
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700584 Variable* _result = NULL;
585 if (0 == strcmp(method->type.type.data, "void")) {
586 block->Add(realCall);
587 } else {
588 _result = new Variable(decl->returnType, "_result",
589 decl->returnTypeDimension);
590 block->Add(new VariableDeclaration(_result, realCall));
591
Joe Onorato3d0e06f2011-09-02 15:28:36 -0700592 // need the result RpcData
593 if (first) {
594 block->Add(new Assignment(serviceBaseClass->resultData,
595 new NewExpression(RPC_DATA_TYPE)));
596 first = false;
597 }
598
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700599 // marshall the return value
600 generate_write_to_data(decl->returnType, block,
601 new StringLiteralExpression("_result"), _result, serviceBaseClass->resultData);
602 }
603
604 // out parameters
605 int i = 0;
606 arg = method->args;
607 while (arg != NULL) {
608 Type* t = NAMES.Search(arg->type.type.data);
609 Variable* v = stubArgs.Get(i++);
610
611 if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
Joe Onorato3d0e06f2011-09-02 15:28:36 -0700612 // need the result RpcData
613 if (first) {
614 block->Add(new Assignment(serviceBaseClass->resultData,
615 new NewExpression(RPC_DATA_TYPE)));
616 first = false;
617 }
618
619
Joe Onoratoc596cfe2011-08-30 17:24:17 -0700620 generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
621 v, serviceBaseClass->resultData);
622 }
623
624 arg = arg->next;
625 }
626}
627
628static void
629generate_method(const method_type* method, RpcProxyClass* proxyClass,
630 ServiceBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
631 int index)
632{
633 // == the callback interface for results =================================
634 // the service base class
635 Type* resultsInterfaceType = generate_results_method(method, proxyClass);
636
637 // == the method in the proxy class =====================================
638 generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
639
640 // == the method in the result dispatcher class =========================
641 if (resultsInterfaceType != NULL) {
642 generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
643 index);
644 }
645
646 // == the dispatch method in the service base class ======================
647 generate_service_base_methods(method, serviceBaseClass);
648}
649
650Class*
651generate_rpc_interface_class(const interface_type* iface)
652{
653 // the proxy class
654 InterfaceType* interfaceType = static_cast<InterfaceType*>(
655 NAMES.Find(iface->package, iface->name.data));
656 RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
657
658 // the service base class
659 ServiceBaseClass* base = new ServiceBaseClass(iface);
660 proxy->elements.push_back(base);
661
662 // the result dispatcher
663 ResultDispatcherClass* results = new ResultDispatcherClass();
664
665 // all the declared methods of the proxy
666 int index = 0;
667 interface_item_type* item = iface->interface_items;
668 while (item != NULL) {
669 if (item->item_type == METHOD_TYPE) {
670 generate_method((method_type*)item, proxy, base, results, index);
671 }
672 item = item->next;
673 index++;
674 }
675 base->DoneWithMethods();
676
677 // only add this if there are methods with results / out parameters
678 if (results->needed) {
679 proxy->elements.push_back(results);
680 }
681
682 return proxy;
683}
684