Home | History | Annotate | Download | only in jsonrpc
      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