321d23ffdc01b329820862a2679ff5ada81dac22
[controller.git] / opendaylight / config / config-util / src / main / java / org / opendaylight / controller / config / util / jolokia / ListableJolokiaClient.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.config.util.jolokia;
9
10 import java.util.ArrayList;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Map.Entry;
18 import java.util.Set;
19 import java.util.regex.Pattern;
20
21 import javax.management.InstanceNotFoundException;
22 import javax.management.MalformedObjectNameException;
23 import javax.management.ObjectName;
24
25 import org.jolokia.client.J4pClient;
26 import org.jolokia.client.exception.J4pException;
27 import org.jolokia.client.exception.J4pRemoteException;
28 import org.jolokia.client.request.J4pExecRequest;
29 import org.jolokia.client.request.J4pListRequest;
30 import org.jolokia.client.request.J4pQueryParameter;
31 import org.jolokia.client.request.J4pReadRequest;
32 import org.jolokia.client.request.J4pRequest;
33 import org.jolokia.client.request.J4pResponse;
34 import org.json.simple.JSONArray;
35 import org.json.simple.JSONObject;
36 import org.opendaylight.controller.config.api.ConflictingVersionException;
37 import org.opendaylight.controller.config.api.ValidationException;
38 import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
39 import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
40 import org.opendaylight.controller.config.util.AttributeEntry;
41
42
43 abstract class ListableJolokiaClient {
44     protected final J4pClient j4pClient;
45     protected final String url;
46     protected final ObjectName objectName;
47
48     public ListableJolokiaClient(String url, ObjectName objectName) {
49         if (url == null) {
50             throw new NullPointerException("Parameter 'url' is null");
51         }
52         if (!url.endsWith("/")) {
53             throw new IllegalArgumentException(
54                     "Parameter 'url' must end with '/'");
55         }
56
57         this.url = url;
58         this.j4pClient = new J4pClient(url);
59         this.objectName = objectName;
60     }
61
62     public ObjectName getObjectName() {
63         return objectName;
64     }
65
66     protected <R extends J4pResponse<T>, T extends J4pRequest> R execute(
67             T pRequest) {
68         try {
69             Map<J4pQueryParameter, String> pProcessingOptions = new HashMap<J4pQueryParameter, String>();
70             pProcessingOptions
71                     .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true");
72             pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION,
73                     "true");
74             return j4pClient.execute(pRequest, "POST", pProcessingOptions);
75         } catch (J4pRemoteException e) {
76             tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue());
77             throw new RuntimeException(e.getRemoteStackTrace(), e);
78         } catch (J4pException e) {
79             throw new RuntimeException(e);
80         }
81     }
82
83     protected void tryToConvertException(String remoteStackTrace,
84             JSONObject errorValue) {
85         String conflictPrefix = ConflictingVersionException.class.getName()
86                 + ": ";
87         if (remoteStackTrace.startsWith(conflictPrefix)) {
88             remoteStackTrace = remoteStackTrace.substring(conflictPrefix
89                     .length());
90             Pattern p = Pattern.compile("\r?\n");
91             remoteStackTrace = Arrays.asList(p.split(remoteStackTrace))
92                     .iterator().next();
93             throw new ConflictingVersionException(remoteStackTrace);
94         }
95         String validationExceptionPrefix = ValidationException.class.getName();
96         if (remoteStackTrace.startsWith(validationExceptionPrefix)) {
97             throw createValidationExceptionFromJSONObject(errorValue);
98         }
99     }
100
101     static ValidationException createValidationExceptionFromJSONObject(
102             JSONObject errorValue) {
103         String fValsKey = "failedValidations";
104         JSONObject failedVals = (JSONObject) errorValue.get(fValsKey);
105
106         checkArgument(
107                 !failedVals.isEmpty(),
108                 fValsKey + " was not present in received JSON: "
109                         + errorValue.toJSONString());
110         Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValsMap = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
111
112         for (Object key : failedVals.keySet()) {
113             checkArgument(key instanceof String, "Unexpected key " + key
114                     + ", expected instance of String");
115             Map<String, ExceptionMessageWithStackTrace> innerMap = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
116             for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) {
117                 checkArgument(innerKey instanceof String, "Unexpected key "
118                         + innerKey + ", expected instance of String");
119                 JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals
120                         .get(key)).get(innerKey));
121                 Object mess = exWithStackTraceVal.get("message");
122                 Object stack = exWithStackTraceVal.get("trace");
123                 checkArgument(mess != null && stack != null,
124                         "\"Message\" and \"trace\" elements expected in received json: "
125                                 + errorValue.toJSONString());
126                 innerMap.put(innerKey.toString(),
127                         new ExceptionMessageWithStackTrace((String) mess,
128                                 (String) stack));
129             }
130             failedValsMap.put((String) key, innerMap);
131         }
132         return new ValidationException(failedValsMap);
133     }
134
135     private static void checkArgument(boolean b, String string) {
136         if (b == false)
137             throw new IllegalArgumentException(string);
138     }
139
140     public String getUrl() {
141         return url;
142     }
143
144     public Map<String, AttributeEntry> getAttributes(ObjectName on) {
145         J4pListRequest req = new J4pListRequest(on);
146         J4pResponse<J4pListRequest> response = execute(req);
147         JSONObject listJSONResponse = response.getValue();
148         JSONObject attributes = (JSONObject) listJSONResponse.get("attr");
149
150         // Empty attributes list
151         if(attributes == null)
152             return Collections.emptyMap();
153
154         Map<String, JSONObject> listMap = new HashMap<>();
155
156         for (Object entryObject : attributes.entrySet()) {
157             Entry<String, Object> entry = (Entry<String, Object>) entryObject;
158             JSONObject entryVal = (JSONObject) entry.getValue();
159
160             // read value
161             listMap.put(entry.getKey(), entryVal);
162         }
163         J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet()
164                 .toArray(new String[0]));
165         J4pResponse<J4pReadRequest> readResponse = execute(j4pReadRequest);
166         Object readResponseValue = readResponse.getValue();
167         // readResponseValue can be String if there is just one attribute or
168         // JSONObject
169         Map<String, Object> attribsToValues = new HashMap<String, Object>();
170         if (readResponseValue instanceof JSONObject) {
171             JSONObject readJSONResponse = (JSONObject) readResponseValue;
172             for (Object entryObject : readJSONResponse.entrySet()) {
173                 Entry<String, Object> entry = (Entry<String, Object>) entryObject;
174                 String key = entry.getKey();
175                 Object value = entry.getValue();
176                 attribsToValues.put(key, value);
177             }
178         }
179
180         Map<String, AttributeEntry> resultMap = new HashMap<String, AttributeEntry>();
181         for (Entry<String, JSONObject> entry : listMap.entrySet()) {
182             String key = entry.getKey();
183             Object value = attribsToValues.size() > 0 ? attribsToValues
184                     .get(key) : readResponseValue;
185             JSONObject listJSON = entry.getValue();
186             String description = (String) listJSON.get("desc");
187             String type = (String) listJSON.get("type");
188             boolean rw = (Boolean) listJSON.get("rw");
189             AttributeEntry attributeEntry = new AttributeEntry(key,
190                     description, value, type, rw);
191             resultMap.put(key, attributeEntry);
192         }
193
194         return resultMap;
195     }
196
197     public String getConfigBeanDescripton(ObjectName on) {
198         J4pListRequest req = new J4pListRequest(on);
199         J4pResponse<J4pListRequest> response = execute(req);
200         JSONObject jsonDesc = response.getValue();
201         Object description = jsonDesc.get("desc");
202         return description == null ? null : description.toString();
203     }
204
205     protected List<ObjectName> jsonArrayToObjectNames(JSONArray jsonArray) {
206         List<ObjectName> result = new ArrayList<>(jsonArray.size());
207         for (Object entry : jsonArray) {
208             JSONObject jsonObject = (JSONObject) entry;
209             String objectNameString = (String) jsonObject.get("objectName");
210             try {
211                 result.add(new ObjectName(objectNameString));
212             } catch (MalformedObjectNameException e) {
213                 throw new IllegalStateException("Cannot convert "
214                         + objectNameString + " to ObjectName", e);
215             }
216         }
217         return result;
218     }
219
220     protected ObjectName extractObjectName(J4pResponse<J4pExecRequest> resp) {
221         JSONObject jsonResponse = resp.getValue();
222         return extractObjectName(jsonResponse);
223     }
224
225     protected ObjectName extractObjectName(JSONObject jsonResponse) {
226         String result = jsonResponse.get("objectName").toString();
227         return ObjectNameUtil.createON(result);
228     }
229
230     protected Set<ObjectName> lookupSomething(String signature,
231             Object[] parameters) {
232         J4pExecRequest req = new J4pExecRequest(objectName, signature,
233                 parameters);
234         JSONArray jsonArray = execute(req).getValue();
235         return new HashSet<>(jsonArrayToObjectNames(jsonArray));
236     }
237
238     public Set<ObjectName> lookupConfigBeans() {
239         return lookupSomething("lookupConfigBeans()", new Object[0]);
240     }
241
242     public Set<ObjectName> lookupConfigBeans(String ifcName) {
243         return lookupSomething("lookupConfigBeans(java.lang.String)",
244                 new Object[] { ifcName });
245     }
246
247     public Set<ObjectName> lookupConfigBeans(String ifcName, String instanceName) {
248         return lookupSomething(
249                 "lookupConfigBeans(java.lang.String,java.lang.String)",
250                 new Object[] { ifcName, instanceName });
251     }
252
253     public ObjectName lookupConfigBean(String ifcName, String instanceName)
254             throws InstanceNotFoundException {
255         J4pExecRequest req = new J4pExecRequest(objectName,
256                 "lookupConfigBean(java.lang.String,java.lang.String)",
257                 new Object[] { ifcName, instanceName });
258         try {
259             J4pResponse<J4pExecRequest> resp = execute(req);
260             return extractObjectName(resp);
261         } catch (RuntimeException e) {
262             if (e.getMessage() != null
263                     && e.getMessage().startsWith(
264                             InstanceNotFoundException.class.getName()))
265                 throw new InstanceNotFoundException();
266             throw e;
267         }
268     }
269
270     public Set<String> getAvailableModuleNames() {
271         J4pReadRequest req = new J4pReadRequest(objectName,
272                 "AvailableModuleNames");
273         List<String> value = execute(req).getValue();
274         return new HashSet<>(value);
275     }
276 }