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