--- /dev/null
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.util.jolokia;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Pattern;
+
+import javax.management.InstanceNotFoundException;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.jolokia.client.J4pClient;
+import org.jolokia.client.exception.J4pException;
+import org.jolokia.client.exception.J4pRemoteException;
+import org.jolokia.client.request.J4pExecRequest;
+import org.jolokia.client.request.J4pListRequest;
+import org.jolokia.client.request.J4pQueryParameter;
+import org.jolokia.client.request.J4pReadRequest;
+import org.jolokia.client.request.J4pRequest;
+import org.jolokia.client.request.J4pResponse;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.api.ValidationException;
+import org.opendaylight.controller.config.api.ValidationException.ExceptionMessageWithStackTrace;
+import org.opendaylight.controller.config.api.jmx.ObjectNameUtil;
+import org.opendaylight.controller.config.util.AttributeEntry;
+
+abstract class ListableJolokiaClient {
+ protected final J4pClient j4pClient;
+ protected final String url;
+ protected final ObjectName objectName;
+
+ public ListableJolokiaClient(String url, ObjectName objectName) {
+ if (url == null) {
+ throw new NullPointerException("Parameter 'url' is null");
+ }
+ if (!url.endsWith("/")) {
+ throw new IllegalArgumentException(
+ "Parameter 'url' must end with '/'");
+ }
+
+ this.url = url;
+ this.j4pClient = new J4pClient(url);
+ this.objectName = objectName;
+ }
+
+ public ObjectName getObjectName() {
+ return objectName;
+ }
+
+ protected <R extends J4pResponse<T>, T extends J4pRequest> R execute(
+ T pRequest) {
+ try {
+ Map<J4pQueryParameter, String> pProcessingOptions = new HashMap<J4pQueryParameter, String>();
+ pProcessingOptions
+ .put(J4pQueryParameter.INCLUDE_STACKTRACE, "true");
+ pProcessingOptions.put(J4pQueryParameter.SERIALIZE_EXCEPTION,
+ "true");
+ return j4pClient.execute(pRequest, "POST", pProcessingOptions);
+ } catch (J4pRemoteException e) {
+ tryToConvertException(e.getRemoteStackTrace(), e.getErrorValue());
+ throw new RuntimeException(e.getRemoteStackTrace(), e);
+ } catch (J4pException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void tryToConvertException(String remoteStackTrace,
+ JSONObject errorValue) {
+ String conflictPrefix = ConflictingVersionException.class.getName()
+ + ": ";
+ if (remoteStackTrace.startsWith(conflictPrefix)) {
+ remoteStackTrace = remoteStackTrace.substring(conflictPrefix
+ .length());
+ Pattern p = Pattern.compile("\r?\n");
+ remoteStackTrace = Arrays.asList(p.split(remoteStackTrace))
+ .iterator().next();
+ throw new ConflictingVersionException(remoteStackTrace);
+ }
+ String validationExceptionPrefix = ValidationException.class.getName();
+ if (remoteStackTrace.startsWith(validationExceptionPrefix)) {
+ throw createValidationExceptionFromJSONObject(errorValue);
+ }
+ }
+
+ static ValidationException createValidationExceptionFromJSONObject(
+ JSONObject errorValue) {
+ String fValsKey = "failedValidations";
+ JSONObject failedVals = (JSONObject) errorValue.get(fValsKey);
+
+ checkArgument(
+ !failedVals.isEmpty(),
+ fValsKey + " was not present in received JSON: "
+ + errorValue.toJSONString());
+ Map<String, Map<String, ExceptionMessageWithStackTrace>> failedValsMap = new HashMap<String, Map<String, ExceptionMessageWithStackTrace>>();
+
+ for (Object key : failedVals.keySet()) {
+ checkArgument(key instanceof String, "Unexpected key " + key
+ + ", expected instance of String");
+ Map<String, ExceptionMessageWithStackTrace> innerMap = new HashMap<String, ValidationException.ExceptionMessageWithStackTrace>();
+ for (Object innerKey : ((JSONObject) failedVals.get(key)).keySet()) {
+ checkArgument(innerKey instanceof String, "Unexpected key "
+ + innerKey + ", expected instance of String");
+ JSONObject exWithStackTraceVal = (JSONObject) (((JSONObject) failedVals
+ .get(key)).get(innerKey));
+ Object mess = exWithStackTraceVal.get("message");
+ Object stack = exWithStackTraceVal.get("trace");
+ checkArgument(mess != null && stack != null,
+ "\"Message\" and \"trace\" elements expected in received json: "
+ + errorValue.toJSONString());
+ innerMap.put(innerKey.toString(),
+ new ExceptionMessageWithStackTrace((String) mess,
+ (String) stack));
+ }
+ failedValsMap.put((String) key, innerMap);
+ }
+ return new ValidationException(failedValsMap);
+ }
+
+ private static void checkArgument(boolean b, String string) {
+ if (b == false)
+ throw new IllegalArgumentException(string);
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public Map<String, AttributeEntry> getAttributes(ObjectName on) {
+ J4pListRequest req = new J4pListRequest(on);
+ J4pResponse<J4pListRequest> response = execute(req);
+ JSONObject listJSONResponse = response.getValue();
+ JSONObject attributes = (JSONObject) listJSONResponse.get("attr");
+ Map<String, JSONObject> listMap = new HashMap<String, JSONObject>();
+ for (Object entryObject : attributes.entrySet()) {
+ Entry<String, Object> entry = (Entry<String, Object>) entryObject;
+ JSONObject entryVal = (JSONObject) entry.getValue();
+
+ // read value
+ listMap.put(entry.getKey(), entryVal);
+ }
+ J4pReadRequest j4pReadRequest = new J4pReadRequest(on, listMap.keySet()
+ .toArray(new String[0]));
+ J4pResponse<J4pReadRequest> readResponse = execute(j4pReadRequest);
+ Object readResponseValue = readResponse.getValue();
+ // readResponseValue can be String if there is just one attribute or
+ // JSONObject
+ Map<String, Object> attribsToValues = new HashMap<String, Object>();
+ if (readResponseValue instanceof JSONObject) {
+ JSONObject readJSONResponse = (JSONObject) readResponseValue;
+ for (Object entryObject : readJSONResponse.entrySet()) {
+ Entry<String, Object> entry = (Entry<String, Object>) entryObject;
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ attribsToValues.put(key, value);
+ }
+ }
+
+ Map<String, AttributeEntry> resultMap = new HashMap<String, AttributeEntry>();
+ for (Entry<String, JSONObject> entry : listMap.entrySet()) {
+ String key = entry.getKey();
+ Object value = attribsToValues.size() > 0 ? attribsToValues
+ .get(key) : readResponseValue;
+ JSONObject listJSON = entry.getValue();
+ String description = (String) listJSON.get("desc");
+ String type = (String) listJSON.get("type");
+ boolean rw = (Boolean) listJSON.get("rw");
+ AttributeEntry attributeEntry = new AttributeEntry(key,
+ description, value, type, rw);
+ resultMap.put(key, attributeEntry);
+ }
+
+ return resultMap;
+ }
+
+ public String getConfigBeanDescripton(ObjectName on) {
+ J4pListRequest req = new J4pListRequest(on);
+ J4pResponse<J4pListRequest> response = execute(req);
+ JSONObject jsonDesc = response.getValue();
+ Object description = jsonDesc.get("desc");
+ return description == null ? null : description.toString();
+ }
+
+ protected List<ObjectName> jsonArrayToObjectNames(JSONArray jsonArray) {
+ List<ObjectName> result = new ArrayList<>(jsonArray.size());
+ for (Object entry : jsonArray) {
+ JSONObject jsonObject = (JSONObject) entry;
+ String objectNameString = (String) jsonObject.get("objectName");
+ try {
+ result.add(new ObjectName(objectNameString));
+ } catch (MalformedObjectNameException e) {
+ throw new IllegalStateException("Cannot convert "
+ + objectNameString + " to ObjectName", e);
+ }
+ }
+ return result;
+ }
+
+ protected ObjectName extractObjectName(J4pResponse<J4pExecRequest> resp) {
+ JSONObject jsonResponse = resp.getValue();
+ return extractObjectName(jsonResponse);
+ }
+
+ protected ObjectName extractObjectName(JSONObject jsonResponse) {
+ String result = jsonResponse.get("objectName").toString();
+ return ObjectNameUtil.createON(result);
+ }
+
+ protected Set<ObjectName> lookupSomething(String signature,
+ Object[] parameters) {
+ J4pExecRequest req = new J4pExecRequest(objectName, signature,
+ parameters);
+ JSONArray jsonArray = execute(req).getValue();
+ return new HashSet<>(jsonArrayToObjectNames(jsonArray));
+ }
+
+ public Set<ObjectName> lookupConfigBeans() {
+ return lookupSomething("lookupConfigBeans()", new Object[0]);
+ }
+
+ public Set<ObjectName> lookupConfigBeans(String ifcName) {
+ return lookupSomething("lookupConfigBeans(java.lang.String)",
+ new Object[] { ifcName });
+ }
+
+ public Set<ObjectName> lookupConfigBeans(String ifcName, String instanceName) {
+ return lookupSomething(
+ "lookupConfigBeans(java.lang.String,java.lang.String)",
+ new Object[] { ifcName, instanceName });
+ }
+
+ public ObjectName lookupConfigBean(String ifcName, String instanceName)
+ throws InstanceNotFoundException {
+ J4pExecRequest req = new J4pExecRequest(objectName,
+ "lookupConfigBean(java.lang.String,java.lang.String)",
+ new Object[] { ifcName, instanceName });
+ try {
+ J4pResponse<J4pExecRequest> resp = execute(req);
+ return extractObjectName(resp);
+ } catch (RuntimeException e) {
+ if (e.getMessage() != null
+ && e.getMessage().startsWith(
+ InstanceNotFoundException.class.getName()))
+ throw new InstanceNotFoundException();
+ throw e;
+ }
+ }
+
+ public Set<String> getAvailableModuleNames() {
+ J4pReadRequest req = new J4pReadRequest(objectName,
+ "AvailableModuleNames");
+ List<String> value = execute(req).getValue();
+ return new HashSet<>(value);
+ }
+}