JavascriptRpcSourceGenerator.java
package eu.javaexperience.rpc.codegen;
import java.util.Collection;
import java.util.Map;
import eu.javaexperience.rpc.RpcFunction;
import eu.javaexperience.rpc.RpcRequest;
import eu.javaexperience.rpc.function.RpcFunctionParameter;
public class JavascriptRpcSourceGenerator
{
public static final String AJAX_TRANSMIT_SOURCE_CODE =
"function ajaxTransmit(url)\n"+
"{\n"+
" this.is_valuable = function(elem)\n"+
" {\n"+
" return undefined != elem && null != elem;\n"+
" };\n"+
"\n"+
" this.rxtx = function(request, response)\n"+
" {\n"+
" var cb = this.is_valuable();\n"+
"\n"+
" var xhr = new XMLHttpRequest();\n"+
" var ajaxTrans = this;\n"+
" if(this.is_valuable(response))\n"+
" {\n"+
" xhr.open('POST', url);\n"+
" var called = [false];\n"+
" xhr.onreadystatechange = function()\n"+
" {\n"+
" if(called[0])\n"+
" {\n"+
" return;\n"+
" }\n"+
"\n"+
" called[0] = true;\n"+
"\n"+
" if(xhr.status === 200)\n"+
" {\n"+
" var data = JSON.parse(xhr.responseText);\n"+
" if(ajaxTrans.is_valuable(data.r))\n"+
" {\n"+
" response(data.r, null);\n"+
" }\n"+
" else if(ajaxTrans.is_valuable(data.e))\n"+
" {\n"+
" response(null, data.e);\n"+
" }\n"+
" return null;\n"+
" }\n"+
" }\n"+
" xhr.send(JSON.stringify(request));\n"+
" }\n"+
" else\n"+
" {\n"+
" xhr.open('POST', url, false);\n"+
" xhr.send(JSON.stringify(request));\n"+
"\n"+
" var data = JSON.parse(xhr.responseText);\n"+
" if(this.is_valuable(data.r))\n"+
" {\n"+
" return data.r;\n"+
" }\n"+
" else if(this.is_valuable(data.e))\n"+
" {\n"+
" throw data.e;\n"+
" }\n"+
" return null;\n"+
" }\n"+
" }\n"+
"}\n"+
"\n";
//"ws://"+location.hostname+(location.port ? ':'+location.port: '')+"/system/socket/connect"
public static final String WEBSOCKET_BIDIRECTIONAL_SOURCE =
" window.WebsocketTransfer = function(url, serverRequestHandler)\n"+
" {\n"+
" this.NEXT_PACKET_ID = 0;\n"+
"\n"+ //packet_trace_id => {id, request, handler}\n"+
" this.PENDING_PACKETS = {};\n"+
"\n"+
" this.is_valuable = function(o)\n"+
" {\n"+
" return null != o && undefined != o;\n"+
" }\n"+
"\n"+
" this.is_function = function(o)\n"+
" {\n"+
" return \"function\" === typeof o;\n"+
" }\n"+
"\n"+
" this.serverRequestHandler = serverRequestHandler;\n"+
" this.SOCKET = new WebSocket(url);\n"+
" this.SOCKET.onmessage = function(event)\n"+
" {\n"+
" var data = JSON.parse(event.data);\n"+
" var id = data.t;\n"+
" if(this.is_valuable(id))\n"+
" {\n"+
" var descriptor = this.PENDING_PACKETS[id];\n"+
" delete this.PENDING_PACKETS[id];\n"+
" if(this.is_function(descriptor.handler))\n"+
" {\n"+
" descriptor.handler(descriptor.request, data, event);\n"+
" }\n"+
" }\n"+
" else\n"+
" {\n"+
" if(this.is_function(this.serverRequestHandler))\n"+
" {\n"+
" this.serverRequestHandler(event.data, event);\n"+
" }\n"+
" }\n"+
" }.bind(this);\n"+
"\n"+
" this.request = function(request, handler)\n"+
" {\n"+
" var id = \"c\"+(++this.NEXT_PACKET_ID);\n"+
" request.t = id;\n"+
" this.PENDING_PACKETS[id] =\n"+
" {\n"+
" id: id,\n"+
" request: request,\n"+
" handler: handler\n"+
" };\n"+
"\n"+
" var send = JSON.stringify(request);\n"+
" this.SOCKET.send(send);\n"+
" }\n"+
"\n"+
" this.simple_request = function(send, opt_notify)\n"+
" {\n"+
" this.request\n"+
" (\n"+
" send,\n"+
" function(req, response, event)\n"+
" {\n"+
" if(this.is_function(opt_notify))\n"+
" {\n"+
" opt_notify(req, response, event);\n"+
" }\n"+
" }.bind(this)\n"+
" );\n"+
" }\n"+
"\n"+
" this.rxtx = function(request, cb)\n"+
" {\n"+
" this.simple_request\n"+
" (\n"+
" request,\n"+
" function(req, response, event)\n"+
" {\n"+
" if(this.is_function(cb))\n"+
" {\n"+
" cb(response.r, response.e, req, event);\n"+
" }\n"+
" }.bind(this)\n"+
" );\n"+
" }\n"+
"}";
/**
* ACCEPT OPTION: using_callback_return
*
*
* */
public static RpcSourceBuilder<RpcFunctionParameter, RpcFunction<RpcRequest, RpcFunctionParameter>> BASIC_JAVASCRIPT_SOURCE_BUILDER =
new RpcSourceBuilder<RpcFunctionParameter, RpcFunction<RpcRequest, RpcFunctionParameter>>()
{
@Override
public String buildRpcClientSource(String compilationUnitName, Collection<RpcFunction<RpcRequest, RpcFunctionParameter>> functions, Map<String, Object> options)
{
StringBuilder sb = new StringBuilder();
boolean use_cb = false;
if(null != options && (options.containsKey("using_callback_return") || options.containsKey("async")))
{
use_cb = true;
}
sb.append("function ");
sb.append(compilationUnitName);
sb.append("(conn)");
boolean teavm = false;
if(options.containsKey("teavm"))
{
teavm = true;
}
// konstruktor {
sb.append("\n{\n\tthis.transfer = conn;\n\n");
// }
// segéd metódusok {
/*
sb.append("\tfunction objectToArray($d)\n\t{\n\t\tif (is_object($d))\n\t\t\t$d = get_object_vars($d);\n\t\tif (is_array($d))\n\t\t\treturn array_map(__METHOD__, $d);\n\t\telse\n\t\t\treturn $d;\n\t}\n\n");
sb.append("\tfunction arrayToObject($d)\n\t{\n\t\tif (is_array($d))\n\t\t\treturn (object) array_map(__METHOD__, $d);\n\t\telse\n\t\t\treturn $d;\n\t}\n\n");
sb.append("\tprivate function sendArray($arr)\n\t{\n\t\tfwrite($this->socket, (json_encode( $this->arrayToObject($arr))).chr(10));\n\t}\n\n");
sb.append("\tprivate function receiveArray()\n\t{\n\t\t$str = fgets($this->socket);\n\n\t\tif($str === false)\n\t\t\tthrow new Exception(\"A kacsolat bezárult!\");\n\t\t$array = $this->objectToArray(json_decode($str));\n\n\t\t if(isset($array['e']))\n\t\t\tthrow new Exception(var_export($array['e'],true));\n\n\t\treturn array_key_exists('r',$array)?$array['r']:null;\n\t}\n\n");
sb.append("\tprivate function close()\n\t{\n\t\t$this->sendArray(array('a'=>'close'));\n\t\tfclose($this->socket);\n\t}\n\n");
*/
//sb.append("\tprivate function rxtx($arr)\n\t{\n\t\t$this->sendArray($arr);\n\t\treturn $this->receiveArray();\n\t}\n\n");
// }
//destruktor
//sb.append("\tpublic function __destruct()\n\t{\n\t\t$this->close();\n\t}\n\n");
//metódusok
for(RpcFunction<RpcRequest, RpcFunctionParameter> f:functions)
{
String comment = JavaRpcExportTools.renderFunctionComment(f);
if(null != comment)
{
sb.append(comment);
}
sb.append("\tthis.");
if(teavm)
{
sb.append("$");
}
sb.append(f.getMethodName());
sb.append(" = function(");
/*if(teavm)
{
sb.append("$this, ");
}*/
RpcFunctionParameter[] params = f.getParameterClasses();
if(use_cb)
{
sb.append("callback");
}
for(int p=0;p<params.length;p++)
{
if(use_cb || p != 0)
{
sb.append(", ");
}
sb.append((char)('a'+p));
}
sb.append(")\n\t{\n\t\t");
if(f.getReturningClass() != null && !void.class.equals(f.getReturningClass()))
{
sb.append("return ");
}
if(teavm)
{
//sb.append("this.transfer.$publish(null, {'f': '");
sb.append("this.transfer.$publish({'f': '");
}
else
{
sb.append("this.transfer.rxtx({'f': '");
}
sb.append(f.getMethodName());
sb.append("', 'p' : [");
for(int p=0;p<params.length;p++)
{
if(0 != p)
{
sb.append(", ");
}
sb.append((char)('a'+p));
}
sb.append("]}, ");
sb.append(use_cb?"callback":"null");
sb.append(");\n\t};\n\n");
}
sb.append("};\n");
return sb.toString();
}
};
}