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