1 package org.opendaylight.ovsdb.lib.jsonrpc;
3 import com.fasterxml.jackson.core.JsonProcessingException;
4 import com.fasterxml.jackson.databind.JavaType;
5 import com.fasterxml.jackson.databind.JsonNode;
6 import com.fasterxml.jackson.databind.ObjectMapper;
7 import com.fasterxml.jackson.databind.type.TypeFactory;
8 import com.google.common.collect.Maps;
9 import com.google.common.reflect.Reflection;
10 import com.google.common.reflect.TypeToken;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import com.google.common.util.concurrent.SettableFuture;
14 import org.opendaylight.controller.sal.core.Node;
15 import org.opendaylight.ovsdb.lib.message.OVSDB;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
19 import java.lang.reflect.InvocationHandler;
20 import java.lang.reflect.Method;
21 import java.util.List;
23 import java.util.UUID;
24 import io.netty.channel.Channel;
26 public class JsonRpcEndpoint {
28 protected static final Logger logger = LoggerFactory.getLogger(JsonRpcEndpoint.class);
30 public class CallContext {
32 JsonRpc10Request request;
33 SettableFuture<Object> future;
35 public CallContext(JsonRpc10Request request, Method method, SettableFuture<Object> future) {
37 this.request = request;
41 public Method getMethod() {
45 public JsonRpc10Request getRequest() {
49 public SettableFuture<Object> getFuture() {
54 ObjectMapper objectMapper;
56 Map<String, CallContext> methodContext = Maps.newHashMap();
57 Map<Node, OVSDB.Callback> requestCallbacks = Maps.newHashMap();
59 public JsonRpcEndpoint(ObjectMapper objectMapper, Channel channel) {
60 this.objectMapper = objectMapper;
61 this.nettyChannel = channel;
64 public <T> T getClient(final Node node, Class<T> klazz) {
66 return Reflection.newProxy(klazz, new InvocationHandler() {
68 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
69 if (method.getName().equals(OVSDB.REGISTER_CALLBACK_METHOD)) {
70 if ((args == null) || args.length != 1 || !(args[0] instanceof OVSDB.Callback)) return false;
71 requestCallbacks.put(node, (OVSDB.Callback)args[0]);
75 JsonRpc10Request request = new JsonRpc10Request(UUID.randomUUID().toString());
76 request.setMethod(method.getName());
78 if (args != null && args.length != 0) {
79 List<Object> params = null;
81 if (args.length == 1) {
82 if (args[0] instanceof Params) {
83 params = ((Params) args[0]).params();
84 } else if (args[0] instanceof List) {
85 params = (List<Object>) args[0];
89 throw new RuntimeException("do not understand this argument yet");
91 request.setParams(params);
95 String s = objectMapper.writeValueAsString(request);
96 logger.debug("{}", s);
98 SettableFuture<Object> sf = SettableFuture.create();
99 methodContext.put(request.getId(), new CallContext(request, method, sf));
101 nettyChannel.writeAndFlush(s);
109 public void processResult(JsonNode response) throws NoSuchMethodException {
111 CallContext returnCtxt = methodContext.get(response.get("id").asText());
112 if (returnCtxt == null) return;
114 if (ListenableFuture.class == returnCtxt.getMethod().getReturnType()) {
115 TypeToken<?> retType = TypeToken.of(
116 returnCtxt.getMethod().getGenericReturnType())
117 .resolveType(ListenableFuture.class.getMethod("get").getGenericReturnType());
118 JavaType javaType = TypeFactory.defaultInstance().constructType (retType.getType());
120 JsonNode result = response.get("result");
121 logger.debug("Response : {}", result.toString());
123 Object result1 = objectMapper.convertValue(result, javaType);
124 JsonNode error = response.get("error");
126 logger.debug("Error : {}", error.toString());
129 returnCtxt.getFuture().set(result1);
132 throw new RuntimeException("donno how to deal with this");
136 public void processRequest(Node node, JsonNode requestJson) {
137 JsonRpc10Request request = new JsonRpc10Request(requestJson.get("id").asText());
138 request.setMethod(requestJson.get("method").asText());
139 logger.debug("Request : {} {}", requestJson.get("method"), requestJson.get("params"));
140 OVSDB.Callback callback = requestCallbacks.get(node);
141 if (callback != null) {
142 Method[] methods = callback.getClass().getDeclaredMethods();
143 for (Method m : methods) {
144 if (m.getName().equals(request.getMethod())) {
145 Class<?>[] parameters = m.getParameterTypes();
146 JsonNode params = requestJson.get("params");
147 Object param = objectMapper.convertValue(params, parameters[1]);
149 m.invoke(callback, node, param);
150 } catch (Exception e) {
158 // Echo dont need any special processing. hence handling it internally.
160 if (request.getMethod().equals("echo")) {
161 JsonRpc10Response response = new JsonRpc10Response(request.getId());
162 response.setError(null);
164 String s = objectMapper.writeValueAsString(response);
165 nettyChannel.writeAndFlush(s);
166 } catch (JsonProcessingException e) {
171 logger.error("No handler for Request : {} on {}",requestJson.toString(), node);
174 public Map<String, CallContext> getMethodContext() {
175 return methodContext;