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  */
     36 public class JsonRpcServer extends SimpleServer {
     37 
     38     private static final String CMD_CLOSE_SESSION = "closeSl4aSession";
     39 
     40     private final RpcReceiverManagerFactory mRpcReceiverManagerFactory;
     41 
     42     // private final String mHandshake;
     43 
     44     /**
     45      * Construct a {@link JsonRpcServer} connected to the provided {@link RpcReceiverManager}.
     46      *
     47      * @param managerFactory the {@link RpcReceiverManager} to register with the server
     48      * @param handshake the secret handshake required for authorization to use this server
     49      */
     50     public JsonRpcServer(RpcReceiverManagerFactory managerFactory, String handshake) {
     51         // mHandshake = handshake;
     52         mRpcReceiverManagerFactory = managerFactory;
     53     }
     54 
     55     @Override
     56     public void shutdown() {
     57         super.shutdown();
     58         // Notify all RPC receiving objects. They may have to clean up some of their state.
     59         for (RpcReceiverManager manager : mRpcReceiverManagerFactory.getRpcReceiverManagers()
     60                 .values()) {
     61             manager.shutdown();
     62         }
     63     }
     64 
     65     @Override
     66     protected void handleRPCConnection(Socket sock, Integer UID, BufferedReader reader,
     67             PrintWriter writer) throws Exception {
     68         RpcReceiverManager receiverManager = null;
     69         Map<Integer, RpcReceiverManager> mgrs = mRpcReceiverManagerFactory.getRpcReceiverManagers();
     70         synchronized (mgrs) {
     71             Log.d("UID " + UID);
     72             Log.d("manager map keys: "
     73                     + mRpcReceiverManagerFactory.getRpcReceiverManagers().keySet());
     74             if (mgrs.containsKey(UID)) {
     75                 Log.d("Look up existing session");
     76                 receiverManager = mgrs.get(UID);
     77             } else {
     78                 Log.d("Create a new session");
     79                 receiverManager = mRpcReceiverManagerFactory.create(UID);
     80             }
     81         }
     82         // boolean passedAuthentication = false;
     83         String data;
     84         while ((data = reader.readLine()) != null) {
     85             Log.v("Session " + UID + " Received: " + data);
     86             JSONObject request = new JSONObject(data);
     87             int id = request.getInt("id");
     88             String method = request.getString("method");
     89             JSONArray params = request.getJSONArray("params");
     90 
     91             MethodDescriptor rpc = receiverManager.getMethodDescriptor(method);
     92             if (rpc == null) {
     93                 send(writer, JsonRpcResult.error(id, new RpcError("Unknown RPC: " + method)), UID);
     94                 continue;
     95             }
     96             try {
     97                 send(writer, JsonRpcResult.result(id, rpc.invoke(receiverManager, params)), UID);
     98             } catch (Throwable t) {
     99                 Log.e("Invocation error.", t);
    100                 send(writer, JsonRpcResult.error(id, t), UID);
    101             }
    102             if (method.equals(CMD_CLOSE_SESSION)) {
    103                 Log.d("Got shutdown signal");
    104                 synchronized (writer) {
    105                     receiverManager.shutdown();
    106                     reader.close();
    107                     writer.close();
    108                     sock.close();
    109                     shutdown();
    110                     mgrs.remove(UID);
    111                 }
    112                 return;
    113             }
    114         }
    115     }
    116 
    117     private void send(PrintWriter writer, JSONObject result, int UID) {
    118         writer.write(result + "\n");
    119         writer.flush();
    120         Log.v("Session " + UID + " Sent: " + result);
    121     }
    122 
    123     @Override
    124     protected void handleConnection(Socket socket) throws Exception {
    125     }
    126 }
    127