Added the missing Copyright headers to most of the java files.
[ovsdb.git] / ovsdb / src / main / java / org / opendaylight / ovsdb / lib / jsonrpc / JsonRpcEndpoint.java
index c3281b30ea5d54129741ccaa9ca78029b7b065d3..8357342b4fb5eb4d657a82514aa05593b9e122e9 100644 (file)
@@ -1,28 +1,39 @@
+/*
+ * Copyright (C) 2013 EBay Software Foundation
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Authors : Ashwin Raveendran, Madhu Venugopal
+ */
 package org.opendaylight.ovsdb.lib.jsonrpc;
 
+import io.netty.channel.Channel;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.opendaylight.controller.sal.core.Node;
+import org.opendaylight.ovsdb.lib.message.OvsdbRPC;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JavaType;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.type.TypeFactory;
 import com.google.common.collect.Maps;
 import com.google.common.reflect.Reflection;
 import com.google.common.reflect.TypeToken;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.SettableFuture;
 
-import org.opendaylight.controller.sal.core.Node;
-import org.opendaylight.ovsdb.plugin.Connection;
-import org.opendaylight.ovsdb.plugin.ConnectionService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
 public class JsonRpcEndpoint {
 
     protected static final Logger logger = LoggerFactory.getLogger(JsonRpcEndpoint.class);
@@ -52,12 +63,13 @@ public class JsonRpcEndpoint {
     }
 
     ObjectMapper objectMapper;
-    ConnectionService service;
+    Channel nettyChannel;
     Map<String, CallContext> methodContext = Maps.newHashMap();
+    Map<Node, OvsdbRPC.Callback> requestCallbacks = Maps.newHashMap();
 
-    public JsonRpcEndpoint(ObjectMapper objectMapper, ConnectionService service) {
+    public JsonRpcEndpoint(ObjectMapper objectMapper, Channel channel) {
         this.objectMapper = objectMapper;
-        this.service = service;
+        this.nettyChannel = channel;
     }
 
     public <T> T getClient(final Node node, Class<T> klazz) {
@@ -65,11 +77,15 @@ public class JsonRpcEndpoint {
         return Reflection.newProxy(klazz, new InvocationHandler() {
             @Override
             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+                if (method.getName().equals(OvsdbRPC.REGISTER_CALLBACK_METHOD)) {
+                    if ((args == null) || args.length != 1 || !(args[0] instanceof OvsdbRPC.Callback)) return false;
+                    requestCallbacks.put(node, (OvsdbRPC.Callback)args[0]);
+                    return true;
+                }
 
                 JsonRpc10Request request = new JsonRpc10Request(UUID.randomUUID().toString());
                 request.setMethod(method.getName());
 
-
                 if (args != null && args.length != 0) {
                     List<Object> params = null;
 
@@ -88,13 +104,12 @@ public class JsonRpcEndpoint {
                 }
 
                 String s = objectMapper.writeValueAsString(request);
-                logger.debug("{}", s);
+                logger.trace("{}", s);
 
                 SettableFuture<Object> sf = SettableFuture.create();
                 methodContext.put(request.getId(), new CallContext(request, method, sf));
 
-                Connection connection = service.getConnection(node);
-                connection.getChannel().writeAndFlush(s);
+                nettyChannel.writeAndFlush(s);
 
                 return sf;
             }
@@ -104,17 +119,25 @@ public class JsonRpcEndpoint {
 
     public void processResult(JsonNode response) throws NoSuchMethodException {
 
+        logger.trace("Response : {}", response.toString());
         CallContext returnCtxt = methodContext.get(response.get("id").asText());
-
-        Class<?> returnType = null;
+        if (returnCtxt == null) return;
 
         if (ListenableFuture.class == returnCtxt.getMethod().getReturnType()) {
             TypeToken<?> retType = TypeToken.of(
                     returnCtxt.getMethod().getGenericReturnType())
                     .resolveType(ListenableFuture.class.getMethod("get").getGenericReturnType());
+            JavaType javaType =  TypeFactory.defaultInstance().constructType (retType.getType());
 
             JsonNode result = response.get("result");
-            Object result1 = objectMapper.convertValue(result, retType.getRawType());
+            logger.trace("Result : {}", result.toString());
+
+            Object result1 = objectMapper.convertValue(result, javaType);
+            JsonNode error = response.get("error");
+            if (error != null && !error.isNull()) {
+                logger.error("Error : {}", error.toString());
+            }
+
             returnCtxt.getFuture().set(result1);
 
         } else {
@@ -125,19 +148,41 @@ public class JsonRpcEndpoint {
     public void processRequest(Node node, JsonNode requestJson) {
         JsonRpc10Request request = new JsonRpc10Request(requestJson.get("id").asText());
         request.setMethod(requestJson.get("method").asText());
+        logger.trace("Request : {} {}", requestJson.get("method"), requestJson.get("params"));
+        OvsdbRPC.Callback callback = requestCallbacks.get(node);
+        if (callback != null) {
+            Method[] methods = callback.getClass().getDeclaredMethods();
+            for (Method m : methods) {
+                if (m.getName().equals(request.getMethod())) {
+                    Class<?>[] parameters = m.getParameterTypes();
+                    JsonNode params = requestJson.get("params");
+                    Object param = objectMapper.convertValue(params, parameters[1]);
+                    try {
+                        m.invoke(callback, node, param);
+                    } catch (IllegalAccessException | InvocationTargetException e) {
+                        logger.error("Unable to invoke callback " + m.getName(), e);
+                    }
+                    return;
+                }
+            }
+        }
 
-        // TODO : Take care of listener interested in the async message from ovsdb-server
-        // and return a result to be sent back.
-        // The following piece of code will help with ECHO handling as is.
-        JsonRpc10Response response = new JsonRpc10Response(request.getId());
-        response.setError(null);
-        try {
-            String s = objectMapper.writeValueAsString(response);
-            Connection connection = service.getConnection(node);
-            connection.getChannel().writeAndFlush(s);
-        } catch (JsonProcessingException e) {
-            e.printStackTrace();
+        // Echo dont need any special processing. hence handling it internally.
+
+        if (request.getMethod().equals("echo")) {
+            JsonRpc10Response response = new JsonRpc10Response(request.getId());
+            response.setError(null);
+            String s = null;
+            try {
+                s = objectMapper.writeValueAsString(response);
+                nettyChannel.writeAndFlush(s);
+            } catch (JsonProcessingException e) {
+                logger.error("Exception while processing JSON string " + s, e );
+            }
+            return;
         }
+
+        logger.error("No handler for Request : {} on {}",requestJson.toString(), node);
     }
 
     public Map<String, CallContext> getMethodContext() {