+/*
+ * 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);
}
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) {
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;
}
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;
}
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 {
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() {