diff options
Diffstat (limited to 'tools/aidl/generate_java_rpc.cpp')
-rw-r--r-- | tools/aidl/generate_java_rpc.cpp | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp new file mode 100644 index 0000000..5e4dacc --- /dev/null +++ b/tools/aidl/generate_java_rpc.cpp @@ -0,0 +1,1001 @@ +#include "generate_java.h" +#include "Type.h" +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +Type* SERVICE_CONTEXT_TYPE = new Type("android.content", + "Context", Type::BUILT_IN, false, false, false); +Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector", + "EventListener", Type::BUILT_IN, false, false, false); +Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector", + "EventListener.Listener", Type::BUILT_IN, false, false, false); +Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker", + Type::BUILT_IN, false, false, false); +Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer", + Type::BUILT_IN, false, false, false); +Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo", + Type::BUILT_IN, false, false, false); +// TODO: Just use Endpoint, so this works for all endpoints. +Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector", + Type::BUILT_IN, false, false, false); +Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc", + "EndpointInfo", true, __FILE__, __LINE__); +Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler", + true, __FILE__, __LINE__); +Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler", + Type::BUILT_IN, false, false, false); +Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true, + __FILE__, __LINE__); + +static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, + Variable* v, Variable* data, Variable** cl); +static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from); +static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, + Variable* data); + +static string +format_int(int n) +{ + char str[20]; + sprintf(str, "%d", n); + return string(str); +} + +static string +class_name_leaf(const string& str) +{ + string::size_type pos = str.rfind('.'); + if (pos == string::npos) { + return str; + } else { + return string(str, pos+1); + } +} + +static string +results_class_name(const string& n) +{ + string str = n; + str[0] = toupper(str[0]); + str.insert(0, "On"); + return str; +} + +static string +results_method_name(const string& n) +{ + string str = n; + str[0] = toupper(str[0]); + str.insert(0, "on"); + return str; +} + +static string +push_method_name(const string& n) +{ + string str = n; + str[0] = toupper(str[0]); + str.insert(0, "push"); + return str; +} + +// ================================================= +class DispatcherClass : public Class +{ +public: + DispatcherClass(const interface_type* iface, Expression* target); + virtual ~DispatcherClass(); + + void AddMethod(const method_type* method); + void DoneWithMethods(); + + Method* processMethod; + Variable* actionParam; + Variable* requestParam; + Variable* rpcContextParam; + Variable* errorParam; + Variable* requestData; + Variable* resultData; + IfStatement* dispatchIfStatement; + Expression* targetExpression; + +private: + void generate_process(); +}; + +DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target) + :Class(), + dispatchIfStatement(NULL), + targetExpression(target) +{ + generate_process(); +} + +DispatcherClass::~DispatcherClass() +{ +} + +void +DispatcherClass::generate_process() +{ + // byte[] process(String action, byte[] params, RpcContext context, RpcError status) + this->processMethod = new Method; + this->processMethod->modifiers = PUBLIC; + this->processMethod->returnType = BYTE_TYPE; + this->processMethod->returnTypeDimension = 1; + this->processMethod->name = "process"; + this->processMethod->statements = new StatementBlock; + + this->actionParam = new Variable(STRING_TYPE, "action"); + this->processMethod->parameters.push_back(this->actionParam); + + this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1); + this->processMethod->parameters.push_back(this->requestParam); + + this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0); + this->processMethod->parameters.push_back(this->rpcContextParam); + + this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0); + this->processMethod->parameters.push_back(this->errorParam); + + this->requestData = new Variable(RPC_DATA_TYPE, "request"); + this->processMethod->statements->Add(new VariableDeclaration(requestData, + new NewExpression(RPC_DATA_TYPE, 1, this->requestParam))); + + this->resultData = new Variable(RPC_DATA_TYPE, "resultData"); + this->processMethod->statements->Add(new VariableDeclaration(this->resultData, + NULL_VALUE)); +} + +void +DispatcherClass::AddMethod(const method_type* method) +{ + arg_type* arg; + + // The if/switch statement + IfStatement* ifs = new IfStatement(); + ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals", + 1, this->actionParam); + StatementBlock* block = ifs->statements = new StatementBlock; + if (this->dispatchIfStatement == NULL) { + this->dispatchIfStatement = ifs; + this->processMethod->statements->Add(dispatchIfStatement); + } else { + this->dispatchIfStatement->elseif = ifs; + this->dispatchIfStatement = ifs; + } + + // The call to decl (from above) + MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data); + + // args + Variable* classLoader = NULL; + VariableFactory stubArgs("_arg"); + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = stubArgs.Get(t); + v->dimension = arg->type.dimension; + + // Unmarshall the parameter + block->Add(new VariableDeclaration(v)); + if (convert_direction(arg->direction.data) & IN_PARAMETER) { + generate_create_from_data(t, block, arg->name.data, v, + this->requestData, &classLoader); + } else { + if (arg->type.dimension == 0) { + block->Add(new Assignment(v, new NewExpression(v->type))); + } + else if (arg->type.dimension == 1) { + generate_new_array(v->type, block, v, this->requestData); + } + else { + fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__, + __LINE__); + } + } + + // Add that parameter to the method call + realCall->arguments.push_back(v); + + arg = arg->next; + } + + // Add a final parameter: RpcContext. Contains data about + // incoming request (e.g., certificate) + realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0)); + + Type* returnType = NAMES.Search(method->type.type.data); + if (returnType == EVENT_FAKE_TYPE) { + returnType = VOID_TYPE; + } + + // the real call + bool first = true; + Variable* _result = NULL; + if (returnType == VOID_TYPE) { + block->Add(realCall); + } else { + _result = new Variable(returnType, "_result", + method->type.dimension); + block->Add(new VariableDeclaration(_result, realCall)); + + // need the result RpcData + if (first) { + block->Add(new Assignment(this->resultData, + new NewExpression(RPC_DATA_TYPE))); + first = false; + } + + // marshall the return value + generate_write_to_data(returnType, block, + new StringLiteralExpression("_result"), _result, this->resultData); + } + + // out parameters + int i = 0; + arg = method->args; + while (arg != NULL) { + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = stubArgs.Get(i++); + + if (convert_direction(arg->direction.data) & OUT_PARAMETER) { + // need the result RpcData + if (first) { + block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE))); + first = false; + } + + generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data), + v, this->resultData); + } + + arg = arg->next; + } +} + +void +DispatcherClass::DoneWithMethods() +{ + if (this->dispatchIfStatement == NULL) { + return; + } + + this->elements.push_back(this->processMethod); + + IfStatement* fallthrough = new IfStatement(); + fallthrough->statements = new StatementBlock; + fallthrough->statements->Add(new ReturnStatement( + new MethodCall(SUPER_VALUE, "process", 4, + this->actionParam, this->requestParam, + this->rpcContextParam, + this->errorParam))); + this->dispatchIfStatement->elseif = fallthrough; + IfStatement* s = new IfStatement; + s->statements = new StatementBlock; + this->processMethod->statements->Add(s); + s->expression = new Comparison(this->resultData, "!=", NULL_VALUE); + s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize"))); + s->elseif = new IfStatement; + s = s->elseif; + s->statements->Add(new ReturnStatement(NULL_VALUE)); +} + +// ================================================= +class RpcProxyClass : public Class +{ +public: + RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType); + virtual ~RpcProxyClass(); + + Variable* endpoint; + Variable* broker; + +private: + void generate_ctor(); + void generate_get_endpoint_info(); +}; + +RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType) + :Class() +{ + this->comment = gather_comments(iface->comments_token->extra); + this->modifiers = PUBLIC; + this->what = Class::CLASS; + this->type = interfaceType; + + // broker + this->broker = new Variable(RPC_BROKER_TYPE, "_broker"); + this->elements.push_back(new Field(PRIVATE, this->broker)); + // endpoint + this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint"); + this->elements.push_back(new Field(PRIVATE, this->endpoint)); + + // methods + generate_ctor(); + generate_get_endpoint_info(); +} + +RpcProxyClass::~RpcProxyClass() +{ +} + +void +RpcProxyClass::generate_ctor() +{ + Variable* broker = new Variable(RPC_BROKER_TYPE, "broker"); + Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = class_name_leaf(this->type->Name()); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(broker); + ctor->parameters.push_back(endpoint); + this->elements.push_back(ctor); + + ctor->statements->Add(new Assignment(this->broker, broker)); + ctor->statements->Add(new Assignment(this->endpoint, endpoint)); +} + +void +RpcProxyClass::generate_get_endpoint_info() +{ + Method* get = new Method; + get->modifiers = PUBLIC; + get->returnType = RPC_ENDPOINT_INFO_TYPE; + get->name = "getEndpointInfo"; + get->statements = new StatementBlock; + this->elements.push_back(get); + + get->statements->Add(new ReturnStatement(this->endpoint)); +} + +// ================================================= +class EventListenerClass : public DispatcherClass +{ +public: + EventListenerClass(const interface_type* iface, Type* listenerType); + virtual ~EventListenerClass(); + + Variable* _listener; + +private: + void generate_ctor(); +}; + +Expression* +generate_get_listener_expression(Type* cast) +{ + return new Cast(cast, new MethodCall(THIS_VALUE, "getView")); +} + +EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType) + :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener")) +{ + this->modifiers = PRIVATE; + this->what = Class::CLASS; + this->type = new Type(iface->package ? iface->package : "", + append(iface->name.data, ".Presenter"), + Type::GENERATED, false, false, false); + this->extends = PRESENTER_BASE_TYPE; + + this->_listener = new Variable(listenerType, "_listener"); + this->elements.push_back(new Field(PRIVATE, this->_listener)); + + // methods + generate_ctor(); +} + +EventListenerClass::~EventListenerClass() +{ +} + +void +EventListenerClass::generate_ctor() +{ + Variable* broker = new Variable(RPC_BROKER_TYPE, "broker"); + Variable* listener = new Variable(this->_listener->type, "listener"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = class_name_leaf(this->type->Name()); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(broker); + ctor->parameters.push_back(listener); + this->elements.push_back(ctor); + + ctor->statements->Add(new MethodCall("super", 2, broker, listener)); + ctor->statements->Add(new Assignment(this->_listener, listener)); +} + +// ================================================= +class ListenerClass : public Class +{ +public: + ListenerClass(const interface_type* iface); + virtual ~ListenerClass(); + + bool needed; + +private: + void generate_ctor(); +}; + +ListenerClass::ListenerClass(const interface_type* iface) + :Class(), + needed(false) +{ + this->comment = "/** Extend this to listen to the events from this class. */"; + this->modifiers = STATIC | PUBLIC ; + this->what = Class::CLASS; + this->type = new Type(iface->package ? iface->package : "", + append(iface->name.data, ".Listener"), + Type::GENERATED, false, false, false); + this->extends = PRESENTER_LISTENER_BASE_TYPE; +} + +ListenerClass::~ListenerClass() +{ +} + +// ================================================= +class EndpointBaseClass : public DispatcherClass +{ +public: + EndpointBaseClass(const interface_type* iface); + virtual ~EndpointBaseClass(); + + bool needed; + +private: + void generate_ctor(); +}; + +EndpointBaseClass::EndpointBaseClass(const interface_type* iface) + :DispatcherClass(iface, THIS_VALUE), + needed(false) +{ + this->comment = "/** Extend this to implement a link service. */"; + this->modifiers = STATIC | PUBLIC | ABSTRACT; + this->what = Class::CLASS; + this->type = new Type(iface->package ? iface->package : "", + append(iface->name.data, ".EndpointBase"), + Type::GENERATED, false, false, false); + this->extends = RPC_CONNECTOR_TYPE; + + // methods + generate_ctor(); +} + +EndpointBaseClass::~EndpointBaseClass() +{ +} + +void +EndpointBaseClass::generate_ctor() +{ + Variable* container = new Variable(RPC_CONTAINER_TYPE, "container"); + Variable* broker = new Variable(RPC_BROKER_TYPE, "broker"); + Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = class_name_leaf(this->type->Name()); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(container); + ctor->parameters.push_back(broker); + ctor->parameters.push_back(place); + this->elements.push_back(ctor); + + ctor->statements->Add(new MethodCall("super", 3, container, broker, place)); +} + +// ================================================= +class ResultDispatcherClass : public Class +{ +public: + ResultDispatcherClass(); + virtual ~ResultDispatcherClass(); + + void AddMethod(int index, const string& name, Method** method, Variable** param); + + bool needed; + Variable* methodId; + Variable* callback; + Method* onResultMethod; + Variable* resultParam; + SwitchStatement* methodSwitch; + +private: + void generate_ctor(); + void generate_onResult(); +}; + +ResultDispatcherClass::ResultDispatcherClass() + :Class(), + needed(false) +{ + this->modifiers = PRIVATE | FINAL; + this->what = Class::CLASS; + this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false); + this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE); + + // methodId + this->methodId = new Variable(INT_TYPE, "methodId"); + this->elements.push_back(new Field(PRIVATE, this->methodId)); + this->callback = new Variable(OBJECT_TYPE, "callback"); + this->elements.push_back(new Field(PRIVATE, this->callback)); + + // methods + generate_ctor(); + generate_onResult(); +} + +ResultDispatcherClass::~ResultDispatcherClass() +{ +} + +void +ResultDispatcherClass::generate_ctor() +{ + Variable* methodIdParam = new Variable(INT_TYPE, "methId"); + Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj"); + Method* ctor = new Method; + ctor->modifiers = PUBLIC; + ctor->name = class_name_leaf(this->type->Name()); + ctor->statements = new StatementBlock; + ctor->parameters.push_back(methodIdParam); + ctor->parameters.push_back(callbackParam); + this->elements.push_back(ctor); + + ctor->statements->Add(new Assignment(this->methodId, methodIdParam)); + ctor->statements->Add(new Assignment(this->callback, callbackParam)); +} + +void +ResultDispatcherClass::generate_onResult() +{ + this->onResultMethod = new Method; + this->onResultMethod->modifiers = PUBLIC; + this->onResultMethod->returnType = VOID_TYPE; + this->onResultMethod->returnTypeDimension = 0; + this->onResultMethod->name = "onResult"; + this->onResultMethod->statements = new StatementBlock; + this->elements.push_back(this->onResultMethod); + + this->resultParam = new Variable(BYTE_TYPE, "result", 1); + this->onResultMethod->parameters.push_back(this->resultParam); + + this->methodSwitch = new SwitchStatement(this->methodId); + this->onResultMethod->statements->Add(this->methodSwitch); +} + +void +ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param) +{ + Method* m = new Method; + m->modifiers = PUBLIC; + m->returnType = VOID_TYPE; + m->returnTypeDimension = 0; + m->name = name; + m->statements = new StatementBlock; + *param = new Variable(BYTE_TYPE, "result", 1); + m->parameters.push_back(*param); + this->elements.push_back(m); + *method = m; + + Case* c = new Case(format_int(index)); + c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam)); + c->statements->Add(new Break()); + + this->methodSwitch->cases.push_back(c); +} + +// ================================================= +static void +generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from) +{ + fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__); + exit(1); +} + +static void +generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v, + Variable* data, Variable** cl) +{ + Expression* k = new StringLiteralExpression(key); + if (v->dimension == 0) { + t->CreateFromRpcData(addTo, k, v, data, cl); + } + if (v->dimension == 1) { + //t->ReadArrayFromRpcData(addTo, v, data, cl); + fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n", + __FILE__, __LINE__); + } +} + +static void +generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data) +{ + if (v->dimension == 0) { + t->WriteToRpcData(addTo, k, v, data, 0); + } + if (v->dimension == 1) { + //t->WriteArrayToParcel(addTo, v, data); + fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n", + __FILE__, __LINE__); + } +} + +// ================================================= +static Type* +generate_results_method(const method_type* method, RpcProxyClass* proxyClass) +{ + arg_type* arg; + + string resultsMethodName = results_method_name(method->name.data); + Type* resultsInterfaceType = new Type(results_class_name(method->name.data), + Type::GENERATED, false, false, false); + + if (!method->oneway) { + Class* resultsClass = new Class; + resultsClass->modifiers = STATIC | PUBLIC; + resultsClass->what = Class::INTERFACE; + resultsClass->type = resultsInterfaceType; + + Method* resultMethod = new Method; + resultMethod->comment = gather_comments(method->comments_token->extra); + resultMethod->modifiers = PUBLIC; + resultMethod->returnType = VOID_TYPE; + resultMethod->returnTypeDimension = 0; + resultMethod->name = resultsMethodName; + if (0 != strcmp("void", method->type.type.data)) { + resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data), + "_result", method->type.dimension)); + } + arg = method->args; + while (arg != NULL) { + if (convert_direction(arg->direction.data) & OUT_PARAMETER) { + resultMethod->parameters.push_back(new Variable( + NAMES.Search(arg->type.type.data), arg->name.data, + arg->type.dimension)); + } + arg = arg->next; + } + resultsClass->elements.push_back(resultMethod); + + if (resultMethod->parameters.size() > 0) { + proxyClass->elements.push_back(resultsClass); + return resultsInterfaceType; + } + } + //delete resultsInterfaceType; + return NULL; +} + +static void +generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass, + ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index) +{ + arg_type* arg; + Method* proxyMethod = new Method; + proxyMethod->comment = gather_comments(method->comments_token->extra); + proxyMethod->modifiers = PUBLIC; + proxyMethod->returnType = VOID_TYPE; + proxyMethod->returnTypeDimension = 0; + proxyMethod->name = method->name.data; + proxyMethod->statements = new StatementBlock; + proxyClass->elements.push_back(proxyMethod); + + // The local variables + Variable* _data = new Variable(RPC_DATA_TYPE, "_data"); + proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE))); + + // Add the arguments + arg = method->args; + while (arg != NULL) { + if (convert_direction(arg->direction.data) & IN_PARAMETER) { + // Function signature + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = new Variable(t, arg->name.data, arg->type.dimension); + proxyMethod->parameters.push_back(v); + + // Input parameter marshalling + generate_write_to_data(t, proxyMethod->statements, + new StringLiteralExpression(arg->name.data), v, _data); + } + arg = arg->next; + } + + // If there is a results interface for this class + Expression* resultParameter; + if (resultsInterfaceType != NULL) { + // Result interface parameter + Variable* resultListener = new Variable(resultsInterfaceType, "_result"); + proxyMethod->parameters.push_back(resultListener); + + // Add the results dispatcher callback + resultsDispatcherClass->needed = true; + resultParameter = new NewExpression(resultsDispatcherClass->type, 2, + new LiteralExpression(format_int(index)), resultListener); + } else { + resultParameter = NULL_VALUE; + } + + // All proxy methods take an error parameter + Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors"); + proxyMethod->parameters.push_back(errorListener); + + // Call the broker + proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"), + "sendRpc", 5, + proxyClass->endpoint, + new StringLiteralExpression(method->name.data), + new MethodCall(_data, "serialize"), + resultParameter, + errorListener)); +} + +static void +generate_result_dispatcher_method(const method_type* method, + ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index) +{ + arg_type* arg; + Method* dispatchMethod; + Variable* dispatchParam; + resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam); + + Variable* classLoader = NULL; + Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData"); + dispatchMethod->statements->Add(new VariableDeclaration(resultData, + new NewExpression(RPC_DATA_TYPE, 1, dispatchParam))); + + // The callback method itself + MethodCall* realCall = new MethodCall( + new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")), + results_method_name(method->name.data)); + + // The return value + { + Type* t = NAMES.Search(method->type.type.data); + if (t != VOID_TYPE) { + Variable* rv = new Variable(t, "rv"); + dispatchMethod->statements->Add(new VariableDeclaration(rv)); + generate_create_from_data(t, dispatchMethod->statements, "_result", rv, + resultData, &classLoader); + realCall->arguments.push_back(rv); + } + } + + VariableFactory stubArgs("arg"); + arg = method->args; + while (arg != NULL) { + if (convert_direction(arg->direction.data) & OUT_PARAMETER) { + // Unmarshall the results + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = stubArgs.Get(t); + dispatchMethod->statements->Add(new VariableDeclaration(v)); + + generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v, + resultData, &classLoader); + + // Add the argument to the callback + realCall->arguments.push_back(v); + } + arg = arg->next; + } + + // Call the callback method + IfStatement* ifst = new IfStatement; + ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE); + dispatchMethod->statements->Add(ifst); + ifst->statements->Add(realCall); +} + +static void +generate_regular_method(const method_type* method, RpcProxyClass* proxyClass, + EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass, + int index) +{ + arg_type* arg; + + // == the callback interface for results ================================ + // the service base class + Type* resultsInterfaceType = generate_results_method(method, proxyClass); + + // == the method in the proxy class ===================================== + generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index); + + // == the method in the result dispatcher class ========================= + if (resultsInterfaceType != NULL) { + generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType, + index); + } + + // == The abstract method that the service developers implement ========== + Method* decl = new Method; + decl->comment = gather_comments(method->comments_token->extra); + decl->modifiers = PUBLIC | ABSTRACT; + decl->returnType = NAMES.Search(method->type.type.data); + decl->returnTypeDimension = method->type.dimension; + decl->name = method->name.data; + arg = method->args; + while (arg != NULL) { + decl->parameters.push_back(new Variable( + NAMES.Search(arg->type.type.data), arg->name.data, + arg->type.dimension)); + arg = arg->next; + } + + // Add the default RpcContext param to all methods + decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0)); + + serviceBaseClass->elements.push_back(decl); + + + // == the dispatch method in the service base class ====================== + serviceBaseClass->AddMethod(method); +} + +static void +generate_event_method(const method_type* method, RpcProxyClass* proxyClass, + EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass, + EventListenerClass* presenterClass, int index) +{ + arg_type* arg; + listenerClass->needed = true; + + // == the push method in the service base class ========================= + Method* push = new Method; + push->modifiers = PUBLIC; + push->name = push_method_name(method->name.data); + push->statements = new StatementBlock; + push->returnType = VOID_TYPE; + serviceBaseClass->elements.push_back(push); + + // The local variables + Variable* _data = new Variable(RPC_DATA_TYPE, "_data"); + push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE))); + + // Add the arguments + arg = method->args; + while (arg != NULL) { + // Function signature + Type* t = NAMES.Search(arg->type.type.data); + Variable* v = new Variable(t, arg->name.data, arg->type.dimension); + push->parameters.push_back(v); + + // Input parameter marshalling + generate_write_to_data(t, push->statements, + new StringLiteralExpression(arg->name.data), v, _data); + + arg = arg->next; + } + + // Send the notifications + push->statements->Add(new MethodCall("pushEvent", 2, + new StringLiteralExpression(method->name.data), + new MethodCall(_data, "serialize"))); + + // == the event callback dispatcher method ==================================== + presenterClass->AddMethod(method); + + // == the event method in the listener base class ===================== + Method* event = new Method; + event->modifiers = PUBLIC; + event->name = method->name.data; + event->statements = new StatementBlock; + event->returnType = VOID_TYPE; + listenerClass->elements.push_back(event); + arg = method->args; + while (arg != NULL) { + event->parameters.push_back(new Variable( + NAMES.Search(arg->type.type.data), arg->name.data, + arg->type.dimension)); + arg = arg->next; + } + + // Add a final parameter: RpcContext. Contains data about + // incoming request (e.g., certificate) + event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0)); +} + +static void +generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType) +{ + // AndroidAtHomePresenter _presenter; + // void startListening(Listener listener) { + // stopListening(); + // _presenter = new Presenter(_broker, listener); + // _presenter.startListening(_endpoint); + // } + // void stopListening() { + // if (_presenter != null) { + // _presenter.stopListening(); + // } + // } + + Variable* _presenter = new Variable(presenterType, "_presenter"); + proxyClass->elements.push_back(new Field(PRIVATE, _presenter)); + + Variable* listener = new Variable(listenerType, "listener"); + + Method* startListeningMethod = new Method; + startListeningMethod->modifiers = PUBLIC; + startListeningMethod->returnType = VOID_TYPE; + startListeningMethod->name = "startListening"; + startListeningMethod->statements = new StatementBlock; + startListeningMethod->parameters.push_back(listener); + proxyClass->elements.push_back(startListeningMethod); + + startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening")); + startListeningMethod->statements->Add(new Assignment(_presenter, + new NewExpression(presenterType, 2, proxyClass->broker, listener))); + startListeningMethod->statements->Add(new MethodCall(_presenter, + "startListening", 1, proxyClass->endpoint)); + + Method* stopListeningMethod = new Method; + stopListeningMethod->modifiers = PUBLIC; + stopListeningMethod->returnType = VOID_TYPE; + stopListeningMethod->name = "stopListening"; + stopListeningMethod->statements = new StatementBlock; + proxyClass->elements.push_back(stopListeningMethod); + + IfStatement* ifst = new IfStatement; + ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE); + stopListeningMethod->statements->Add(ifst); + + ifst->statements->Add(new MethodCall(_presenter, "stopListening")); + ifst->statements->Add(new Assignment(_presenter, NULL_VALUE)); +} + +Class* +generate_rpc_interface_class(const interface_type* iface) +{ + // the proxy class + InterfaceType* interfaceType = static_cast<InterfaceType*>( + NAMES.Find(iface->package, iface->name.data)); + RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType); + + // the listener class + ListenerClass* listener = new ListenerClass(iface); + + // the presenter class + EventListenerClass* presenter = new EventListenerClass(iface, listener->type); + + // the service base class + EndpointBaseClass* base = new EndpointBaseClass(iface); + proxy->elements.push_back(base); + + // the result dispatcher + ResultDispatcherClass* results = new ResultDispatcherClass(); + + // all the declared methods of the proxy + int index = 0; + interface_item_type* item = iface->interface_items; + while (item != NULL) { + if (item->item_type == METHOD_TYPE) { + if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) { + generate_event_method((method_type*)item, proxy, base, listener, presenter, index); + } else { + generate_regular_method((method_type*)item, proxy, base, results, index); + } + } + item = item->next; + index++; + } + presenter->DoneWithMethods(); + base->DoneWithMethods(); + + // only add this if there are methods with results / out parameters + if (results->needed) { + proxy->elements.push_back(results); + } + if (listener->needed) { + proxy->elements.push_back(listener); + proxy->elements.push_back(presenter); + generate_listener_methods(proxy, presenter->type, listener->type); + } + + return proxy; +} |