Skip to content
Advertisement

Logging JSON-RPC calls using jsonrpc4j

I’m sure that if you have used jsonrpc4j (outside a spring container) you will recognise the following standard pattern.

public class MyServletJsonRpc extends HttpServlet {
   private MyService myService;
   private JsonRpcServer jsonRpcServer;

   @Override
   protected void doPost(HttpServletRequest request
                      , HttpServletResponse response) throws IOException {
      jsonRpcServer.handle(request, response);
   }
   @Override
   public void init(ServletConfig config) {
       myService = new MyServiceImpl();
       jsonRpcServer = new JsonRpcServer(myService, MyService.class);
       jsonRpcServer.set...
   }

I am trying to create a log file containing all the JSON requests and JSON responses. i.e. I’d like to log the incoming JSON RPC request before it is deserialised and log the out going request just after it is serialised.

I’ve been reading through the code and there doesn’t seem to be a nice easy way of doing this. Can anyone help?

The solution I have come up with (which works) uses a decorate of sorts but I’m not happy with it:

public class MyServletJsonRpc extends HttpServlet {
   private MyService myService;
   private JsonRpcServer jsonRpcServer;

   @Override
   protected void doPost(HttpServletRequest request
                      , HttpServletResponse response) throws IOException {
      jsonRpcServer.handle(request, response);
   }
   @Override
   public void init(ServletConfig config) {
       myService = new MyServiceImpl();
       ObjectMapper mapper = new MyObjectMapper(null, null, null);
       jsonRpcServer = new MyJsonRpcServer(mapper, myService, null);
       jsonRpcServer.set...
   }
}

Using the following 2 overloaded classes:

class MyObjectMapper extends ObjectMapper {
    private static final Logger L = LoggerFactory.getLogger(MyObjectMapper.class);

    public MyObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
        super(jf, sp, dc);
    }

    @Override
    public void writeValue(OutputStream out, Object value) throws IOException, JsonGenerationException,
JsonMappingException {
        super.writeValue(out, value);
        L.info("Out: " + writeValueAsString(value));
    }

}

and

class MyJsonRpcServer extends JsonRpcServer {
    private static final Logger L = LoggerFactory.getLogger(MyJsonRpcServer.class);

    public MyJsonRpcServer(ObjectMapper mapper, Object handler, Class<?> remoteInterface) {
        super(mapper, handler, remoteInterface);
    }

    @Override
    public void handleNode(JsonNode node, OutputStream ops) throws IOException {
        L.info("In: " + (node == null ? "(null)" : node.toString()));
        super.handleNode(node, ops);
    }
}

I think this looks and feels like a bit of a nasty hack. Is there a better way of doing this?

Advertisement

Answer

The library supports the use of an InvocationListener: https://github.com/briandilley/jsonrpc4j/blob/master/src/main/java/com/googlecode/jsonrpc4j/InvocationListener.java

you can add it to the server in your servlets init() method and all invocations will go through it.

here’s the setter: https://github.com/briandilley/jsonrpc4j/blob/cfdaea92fedf7b43be9d93420df168fe69a5a4fa/src/main/java/com/googlecode/jsonrpc4j/JsonRpcBasicServer.java#L994

So just call server.setInvocationListener and you’re good to go.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement