All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.velasolaris.plugin.controller.rpc.JsonRpcStreamProxy Maven / Gradle / Ivy

The newest version!
package com.velasolaris.plugin.controller.rpc;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.logging.Level;

import com.thetransactioncompany.jsonrpc2.JSONRPC2ParseException;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Request;
import com.thetransactioncompany.jsonrpc2.JSONRPC2Response;
import com.velasolaris.plugin.controller.spi.PluginControllerException;
import com.velasolaris.plugin.util.PluginUtils;

/**
 * Proxy class for JSON-RPC function calls (http://json-rpc.org) using a TCP socket streaming the data.
 *
 * One TCP connection per simulation is used. This is a optimized, high performance implementation.
 *
 * This implementation is not JSON-RPC 2.0 standard compatible as the communication is not over HTTP.
 *
 * Simple custom RPC streaming protocol sending JSON-RPC 2.0 string lines encoded as UTF-8:
 * 
    *
  1. Open TCP socket communication connection *
  2. Send JSON-RPC 2.0 request terminated by EOL. *
  3. Read JSON-RPC 2.0 response terminated by EOL. *
  4. Repeat 2 until simulation has ended. *
  5. Send empty line terminated by EOL to terminate the connection. *
* * EOL = End of line (i.e. \n in Python/Java or Unicode \u000a) * * This client proxy uses parts of http://software.dzhuvinov.com/json-rpc-2.0-base.html. * * The {@link JsonRpcProxy} is similar, but creates for each request a new HTTP (TCP) connection. * Therefore, {@link JsonRpcStreamProxy} is much slower, but JSON-RPC standard conform. * * @author rkurmann * @since Polysun 9.2 * * @see JsonRpcProxy * */ public class JsonRpcStreamProxy extends AbstractJsonRpcProxy { /** TCP socket for streaming the function JSON-RPC requests and JSON-RPC responses. */ private Socket socket; /** PrintWriter using TCP socket for sending the function JSON-RPC requests. */ private PrintWriter socketOut; /** BufferedReader using TCP socket for reading the function JSON-RPC responses. */ private BufferedReader socketIn; /** * Constructor. * * @param rpcServerURL URL of the RPC server for the function calls, e.g. http://localhost:2102/control * @param rpcFunction Name of the RPC function, e.g. controlFlowrate * @param connectionTimeout Connection timeout [ms] 0 may mean wait forever. * @param readTimeout Read timeout [ms] 0 may mean wait forever. * @param verboseLevel Level of verbosity */ protected JsonRpcStreamProxy(URL rpcServerURL, String rpcFunction, int connectionTimeout, int readTimeout, int verboseLevel) { super(rpcServerURL, rpcFunction, connectionTimeout, readTimeout, verboseLevel); } @Override public void disconnectProxy() { if (socket != null) { if (sLog.isLoggable(Level.INFO)) sLog.info("Disconnect proxy"); try { socketIn.close(); } catch (IOException e) { sLog.warning(PluginUtils.getRootCauseStackTrace(e)); } socketOut.print("\n"); // Send empty line as signal to close connection socketOut.close(); // flush() is called before the writer is closed try { socket.close(); } catch (IOException e) { sLog.warning(PluginUtils.getRootCauseStackTrace(e)); } socketIn = null; socketOut = null; socket = null; rpcServerURL = null; } } @Override protected JSONRPC2Response invoke(JSONRPC2Request request) throws JSONRPC2ParseException, IOException, PluginControllerException { getProxy(); socketOut.print(request + "\n"); // Do not use println() since EOL is platform specific socketOut.flush(); // Flush request since println() is not used long startWait = System.currentTimeMillis(); while (!socketIn.ready() && startWait + readTimeout > System.currentTimeMillis()); String rawResponse = socketIn.readLine(); try { return JSONRPC2Response.parse(rawResponse, false, true, false); } catch (NullPointerException e) { throw new PluginControllerException("No valid JSON-RPC response. Probably the RPC server has been stopped.", e); } } /** * Returns a proxy to communicate with the JSON-RPC server. * * @return the proxy * @throws IOException for IO problems * @throws UnknownHostException for host resolving problems */ protected Socket getProxy() throws UnknownHostException, IOException { if (socket == null) { if (verboseLevel >= SimpleRpcPluginController.VERBOSE_LEVEL_DEBUG) { sLog.fine("Create JsonRpcStreamProxy"); } socket = new Socket(rpcServerURL.getHost(), rpcServerURL.getPort()); socket.setPerformancePreferences(0, 2, 1); socket.setTcpNoDelay(true); // Not actually useful here, since our protocol is a ping pong socket.setSoTimeout(readTimeout); socketOut = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true); // new BufferedWriter() is not useful in our case since we send one line in one command, thus no buffering is required socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); } return socket; } /** * Test call. * * @param args Program arguments * * @throws Exception * For any problems */ public static void main(String... args) throws Exception { System.out.println("Start"); URL serverURL = new URL("http://localhost:2102"); int requestID = 0; JsonRpcStreamProxy proxy = new JsonRpcStreamProxy(serverURL, "control", 15000, 15000, 3); JSONRPC2Request request = new JSONRPC2Request("ping", requestID++); JSONRPC2Response response = proxy.invoke(request); if (response.indicatesSuccess()) { System.out.println(response.getResult()); } else { System.out.println(response.getError().getMessage()); } request = new JSONRPC2Request("ping", requestID++); response = proxy.invoke(request); if (response.indicatesSuccess()) { System.out.println(response.getResult()); } else { System.out.println(response.getError().getMessage()); } request = new JSONRPC2Request("print", Arrays.asList(new Object[] { "WOW" }), requestID++); response = proxy.invoke(request); if (response.indicatesSuccess()) { System.out.println(response.getResult()); } else { System.out.println(response.getError().getMessage()); } int num = 1000; long start = System.nanoTime(); for (int i = 0; i < num; i++) { response = proxy.invoke(new JSONRPC2Request("ping", requestID++)); } long stop = System.nanoTime(); System.out.println("@ ping: " + ((stop - start) / 10000 / num) / 100f + "ms"); if (response.indicatesSuccess()) { System.out.println(response.getResult()); } else { System.out.println(response.getError().getMessage()); } System.out.println("End"); System.exit(0); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy