Fixed Transact response handling and updated the operation response for each request
[ovsdb.git] / ovsdb / src / main / java / org / opendaylight / ovsdb / lib / jsonrpc / JsonRpcEndpoint.java
1 package org.opendaylight.ovsdb.lib.jsonrpc;
2
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.node.ArrayNode;
8 import com.fasterxml.jackson.databind.type.TypeFactory;
9 import com.google.common.collect.Maps;
10 import com.google.common.reflect.Reflection;
11 import com.google.common.reflect.TypeToken;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.SettableFuture;
14
15 import org.opendaylight.controller.sal.core.Node;
16 import org.opendaylight.ovsdb.lib.message.Response;
17 import org.opendaylight.ovsdb.plugin.Connection;
18 import org.opendaylight.ovsdb.plugin.ConnectionService;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 import java.lang.reflect.InvocationHandler;
23 import java.lang.reflect.Method;
24 import java.lang.reflect.Type;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.UUID;
29
30 public class JsonRpcEndpoint {
31
32     protected static final Logger logger = LoggerFactory.getLogger(JsonRpcEndpoint.class);
33
34     public class CallContext {
35         Method method;
36         JsonRpc10Request request;
37         SettableFuture<Object> future;
38
39         public CallContext(JsonRpc10Request request, Method method, SettableFuture<Object> future) {
40             this.method = method;
41             this.request = request;
42             this.future = future;
43         }
44
45         public Method getMethod() {
46             return method;
47         }
48
49         public JsonRpc10Request getRequest() {
50             return request;
51         }
52
53         public SettableFuture<Object> getFuture() {
54             return future;
55         }
56     }
57
58     ObjectMapper objectMapper;
59     ConnectionService service;
60     Map<String, CallContext> methodContext = Maps.newHashMap();
61
62     public JsonRpcEndpoint(ObjectMapper objectMapper, ConnectionService service) {
63         this.objectMapper = objectMapper;
64         this.service = service;
65     }
66
67     public <T> T getClient(final Node node, Class<T> klazz) {
68
69         return Reflection.newProxy(klazz, new InvocationHandler() {
70             @Override
71             public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
72
73                 JsonRpc10Request request = new JsonRpc10Request(UUID.randomUUID().toString());
74                 request.setMethod(method.getName());
75
76
77                 if (args != null && args.length != 0) {
78                     List<Object> params = null;
79
80                     if (args.length == 1) {
81                         if (args[0] instanceof Params) {
82                             params = ((Params) args[0]).params();
83                         } else if (args[0] instanceof List) {
84                             params = (List<Object>) args[0];
85                         }
86
87                         if (params == null) {
88                             throw new RuntimeException("do not understand this argument yet");
89                         }
90                         request.setParams(params);
91                     }
92                 }
93
94                 String s = objectMapper.writeValueAsString(request);
95                 logger.debug("{}", s);
96
97                 SettableFuture<Object> sf = SettableFuture.create();
98                 methodContext.put(request.getId(), new CallContext(request, method, sf));
99
100                 Connection connection = service.getConnection(node);
101                 connection.getChannel().writeAndFlush(s);
102
103                 return sf;
104             }
105         }
106         );
107     }
108
109     @SuppressWarnings("deprecation")
110     public void processResult(JsonNode response) throws NoSuchMethodException {
111
112         CallContext returnCtxt = methodContext.get(response.get("id").asText());
113         if (returnCtxt == null) return;
114
115         if (ListenableFuture.class == returnCtxt.getMethod().getReturnType()) {
116             TypeToken<?> retType = TypeToken.of(
117                     returnCtxt.getMethod().getGenericReturnType())
118                     .resolveType(ListenableFuture.class.getMethod("get").getGenericReturnType());
119             JavaType javaType =  TypeFactory.defaultInstance().constructType (retType.getType());
120
121             JsonNode result = response.get("result");
122             logger.debug("Response : {}", result.toString());
123
124             Object result1 = objectMapper.convertValue(result, javaType);
125             JsonNode error = response.get("error");
126             if (error != null) {
127                 logger.debug("Error : {}", error.toString());
128             }
129
130             returnCtxt.getFuture().set(result1);
131
132         } else {
133             throw new RuntimeException("donno how to deal with this");
134         }
135     }
136
137     public void processRequest(Node node, JsonNode requestJson) {
138         JsonRpc10Request request = new JsonRpc10Request(requestJson.get("id").asText());
139         request.setMethod(requestJson.get("method").asText());
140
141         // TODO : Take care of listener interested in the async message from ovsdb-server
142         // and return a result to be sent back.
143         // The following piece of code will help with ECHO handling as is.
144         if (request.getMethod().equals("echo")) {
145             JsonRpc10Response response = new JsonRpc10Response(request.getId());
146             response.setError(null);
147             try {
148                 String s = objectMapper.writeValueAsString(response);
149                 Connection connection = service.getConnection(node);
150                 connection.getChannel().writeAndFlush(s);
151             } catch (JsonProcessingException e) {
152                 e.printStackTrace();
153             }
154         }
155     }
156
157     public Map<String, CallContext> getMethodContext() {
158         return methodContext;
159     }
160 }