1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.googlecode.android_scripting.jsonrpc; 18 19 import java.io.BufferedReader; 20 import java.io.PrintWriter; 21 import java.net.Socket; 22 import java.util.Map; 23 24 import org.json.JSONArray; 25 import org.json.JSONObject; 26 27 import com.googlecode.android_scripting.Log; 28 import com.googlecode.android_scripting.SimpleServer; 29 import com.googlecode.android_scripting.rpc.MethodDescriptor; 30 import com.googlecode.android_scripting.rpc.RpcError; 31 32 /** 33 * A JSON RPC server that forwards RPC calls to a specified receiver object. 34 * 35 * @author Damon Kohler (damonkohler (at) gmail.com) 36 */ 37 public class JsonRpcServer extends SimpleServer { 38 39 private static final String CMD_CLOSE_SESSION = "closeSl4aSession"; 40 41 private final RpcReceiverManagerFactory mRpcReceiverManagerFactory; 42 43 // private final String mHandshake; 44 45 /** 46 * Construct a {@link JsonRpcServer} connected to the provided {@link RpcReceiverManager}. 47 * 48 * @param managerFactory the {@link RpcReceiverManager} to register with the server 49 * @param handshake the secret handshake required for authorization to use this server 50 */ 51 public JsonRpcServer(RpcReceiverManagerFactory managerFactory, String handshake) { 52 // mHandshake = handshake; 53 mRpcReceiverManagerFactory = managerFactory; 54 } 55 56 @Override 57 public void shutdown() { 58 super.shutdown(); 59 // Notify all RPC receiving objects. They may have to clean up some of their state. 60 for (RpcReceiverManager manager : mRpcReceiverManagerFactory.getRpcReceiverManagers() 61 .values()) { 62 manager.shutdown(); 63 } 64 } 65 66 @Override 67 protected void handleRPCConnection(Socket sock, Integer UID, BufferedReader reader, 68 PrintWriter writer) throws Exception { 69 RpcReceiverManager receiverManager = null; 70 Map<Integer, RpcReceiverManager> mgrs = mRpcReceiverManagerFactory.getRpcReceiverManagers(); 71 synchronized (mgrs) { 72 Log.d("UID " + UID); 73 Log.d("manager map keys: " 74 + mRpcReceiverManagerFactory.getRpcReceiverManagers().keySet()); 75 if (mgrs.containsKey(UID)) { 76 Log.d("Look up existing session"); 77 receiverManager = mgrs.get(UID); 78 } else { 79 Log.d("Create a new session"); 80 receiverManager = mRpcReceiverManagerFactory.create(UID); 81 } 82 } 83 // boolean passedAuthentication = false; 84 String data; 85 while ((data = reader.readLine()) != null) { 86 Log.v("Session " + UID + " Received: " + data); 87 JSONObject request = new JSONObject(data); 88 int id = request.getInt("id"); 89 String method = request.getString("method"); 90 JSONArray params = request.getJSONArray("params"); 91 92 MethodDescriptor rpc = receiverManager.getMethodDescriptor(method); 93 if (rpc == null) { 94 send(writer, JsonRpcResult.error(id, new RpcError("Unknown RPC: " + method)), UID); 95 continue; 96 } 97 try { 98 send(writer, JsonRpcResult.result(id, rpc.invoke(receiverManager, params)), UID); 99 } catch (Throwable t) { 100 Log.e("Invocation error.", t); 101 send(writer, JsonRpcResult.error(id, t), UID); 102 } 103 if (method.equals(CMD_CLOSE_SESSION)) { 104 Log.d("Got shutdown signal"); 105 synchronized (writer) { 106 receiverManager.shutdown(); 107 reader.close(); 108 writer.close(); 109 sock.close(); 110 shutdown(); 111 mgrs.remove(UID); 112 } 113 return; 114 } 115 } 116 } 117 118 private void send(PrintWriter writer, JSONObject result, int UID) { 119 writer.write(result + "\n"); 120 writer.flush(); 121 Log.v("Session " + UID + " Sent: " + result); 122 } 123 124 @Override 125 protected void handleConnection(Socket socket) throws Exception { 126 } 127 } 128