blob: d550be5d6a9075281af2823389e05249d08c34b5 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.commands.jolokia;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import org.apache.camel.commands.AbstractCamelController;
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.J4pExecResponse;
import org.jolokia.client.request.J4pReadRequest;
import org.jolokia.client.request.J4pReadResponse;
import org.jolokia.client.request.J4pSearchRequest;
import org.jolokia.client.request.J4pSearchResponse;
import org.jolokia.client.request.J4pVersionRequest;
import org.jolokia.client.request.J4pVersionResponse;
import org.json.simple.JSONObject;
/**
* A {@link org.apache.camel.commands.CamelController} that uses Jolokia Client to connect to remote JVMs which
* has an Jolokia agent running.
*/
public class DefaultJolokiaCamelController extends AbstractCamelController implements JolokiaCamelController {
private Map<String, ObjectName> cache = new HashMap<String, ObjectName>(100);
private J4pClient jolokia;
private String url;
private ObjectName lookupCamelContext(String camelContextName) throws Exception {
ObjectName on = cache.get(camelContextName);
if (on == null) {
ObjectName found = null;
J4pSearchResponse sr = jolokia.execute(new J4pSearchRequest("*:type=context,*"));
if (sr != null) {
for (ObjectName name : sr.getObjectNames()) {
String id = name.getKeyProperty("name");
id = removeLeadingAndEndingQuotes(id);
if (camelContextName.equals(id)) {
found = name;
break;
}
}
}
if (found != null) {
on = found;
cache.put(camelContextName, on);
}
}
return on;
}
@Override
public void using(J4pClient client) {
this.jolokia = client;
this.url = null;
}
@Override
public void connect(String url, String username, String password) throws Exception {
this.jolokia = JolokiaClientFactory.createJolokiaClient(url, username, password);
this.url = url;
}
@Override
public boolean ping() {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
J4pVersionResponse vr;
try {
vr = jolokia.execute(new J4pVersionRequest());
return vr != null && vr.getValue() != null;
} catch (J4pException e) {
return false;
}
}
@Override
public Map<String, Object> getCamelContextInformation(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
Map<String, Object> answer = new LinkedHashMap<String, Object>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=services,name=DefaultTypeConverter", found.getDomain(), found.getKeyProperty("context"));
ObjectName tc = ObjectName.getInstance(pattern);
String pattern2 = String.format("%s:context=%s,type=services,name=DefaultAsyncProcessorAwaitManager", found.getDomain(), found.getKeyProperty("context"));
ObjectName am = ObjectName.getInstance(pattern2);
List<J4pReadRequest> list = new ArrayList<J4pReadRequest>();
list.add(new J4pReadRequest(found));
list.add(new J4pReadRequest(tc));
list.add(new J4pReadRequest(am));
List<J4pReadResponse> rr = jolokia.execute(list);
if (rr != null && rr.size() > 0) {
// camel context attributes
J4pReadResponse first = rr.get(0);
for (String key : first.getAttributes()) {
answer.put(asKey(key), first.getValue(key));
}
// type converter attributes
if (rr.size() >= 2) {
J4pReadResponse second = rr.get(1);
for (String key : second.getAttributes()) {
answer.put("typeConverter." + asKey(key), second.getValue(key));
}
}
// async processor await manager attributes
if (rr.size() >= 3) {
J4pReadResponse second = rr.get(2);
for (String key : second.getAttributes()) {
answer.put("asyncProcessorAwaitManager." + asKey(key), second.getValue(key));
}
}
}
// would be great if there was an api in jolokia to read optional (eg ignore if an mbean does not exists)
answer.put("streamCachingEnabled", false);
try {
pattern = String.format("%s:context=%s,type=services,name=DefaultStreamCachingStrategy", found.getDomain(), found.getKeyProperty("context"));
ObjectName sc = ObjectName.getInstance(pattern);
// there is only a mbean if stream caching is enabled
J4pReadResponse rsc = jolokia.execute(new J4pReadRequest(sc));
if (rsc != null) {
for (String key : rsc.getAttributes()) {
answer.put("streamCaching." + asKey(key), rsc.getValue(key));
}
}
answer.put("streamCachingEnabled", true);
} catch (J4pRemoteException e) {
// ignore
boolean ignore = InstanceNotFoundException.class.getName().equals(e.getErrorType());
if (!ignore) {
throw e;
}
}
// store some data using special names as that is what the core-commands expects
answer.put("name", answer.get("camelId"));
answer.put("status", answer.get("state"));
answer.put("version", answer.get("camelVersion"));
answer.put("suspended", "Suspended".equals(answer.get("state")));
TimeUnit unit = TimeUnit.valueOf((String) answer.get("timeUnit"));
long timeout = (Long) answer.get("timeout");
answer.put("shutdownTimeout", "" + unit.toSeconds(timeout));
answer.put("applicationContextClassLoader", answer.get("applicationContextClassName"));
}
return answer;
}
@Override
public List<Map<String, String>> getCamelContexts() throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
J4pSearchResponse sr = jolokia.execute(new J4pSearchRequest("*:type=context,*"));
List<J4pReadRequest> list = new ArrayList<J4pReadRequest>();
for (ObjectName on : sr.getObjectNames()) {
list.add(new J4pReadRequest(on, "CamelId", "State", "Uptime", "ExchangesTotal", "ExchangesInflight", "ExchangesFailed"));
}
List<J4pReadResponse> lrr = jolokia.execute(list);
for (J4pReadResponse rr : lrr) {
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("name", rr.getValue("CamelId").toString());
row.put("state", rr.getValue("State").toString());
row.put("uptime", rr.getValue("Uptime").toString());
row.put("exchangesTotal", rr.getValue("ExchangesTotal").toString());
row.put("exchangesInflight", rr.getValue("ExchangesInflight").toString());
row.put("exchangesFailed", rr.getValue("ExchangesFailed").toString());
answer.add(row);
}
return answer;
}
@Override
public String getCamelContextStatsAsXml(String camelContextName, boolean fullStats, boolean includeProcessors) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
J4pExecResponse er = jolokia.execute(new J4pExecRequest(found, "dumpRoutesStatsAsXml(boolean,boolean)", fullStats, includeProcessors));
if (er != null) {
String xml = er.getValue();
return xml;
}
}
return null;
}
@Override
public List<Map<String, Object>> browseInflightExchanges(String camelContextName, int limit, boolean sortByLongestDuration) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, Object>> answer = new ArrayList<Map<String, Object>>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=services,name=DefaultInflightRepository", found.getDomain(), found.getKeyProperty("context"));
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse er = jolokia.execute(new J4pExecRequest(on, "browse(int,boolean)", limit, sortByLongestDuration));
if (er != null) {
JSONObject data = er.getValue();
if (data != null) {
for (Object obj : data.values()) {
JSONObject inflight = (JSONObject) obj;
Map<String, Object> row = new LinkedHashMap<String, Object>();
row.put("exchangeId", asString(inflight.get("exchangeId")));
row.put("fromRouteId", asString(inflight.get("fromRouteId")));
row.put("routeId", asString(inflight.get("routeId")));
row.put("nodeId", asString(inflight.get("nodeId")));
row.put("elapsed", asString(inflight.get("elapsed")));
row.put("duration", asString(inflight.get("duration")));
answer.add(row);
}
}
}
}
return answer;
}
@Override
public void startContext(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
jolokia.execute(new J4pExecRequest(found, "start"));
}
}
@Override
public void stopContext(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
jolokia.execute(new J4pExecRequest(found, "stop"));
}
}
@Override
public void suspendContext(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
jolokia.execute(new J4pExecRequest(found, "suspend"));
}
}
@Override
public void resumeContext(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
jolokia.execute(new J4pExecRequest(found, "resume"));
}
}
@Override
public List<Map<String, String>> getRoutes(String camelContextName) throws Exception {
return getRoutes(camelContextName, null);
}
@Override
public List<Map<String, String>> getRoutes(String camelContextName, String filter) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
ObjectName found = camelContextName != null ? lookupCamelContext(camelContextName) : null;
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,*", found.getDomain(), found.getKeyProperty("context"));
J4pSearchResponse sr = jolokia.execute(new J4pSearchRequest(pattern));
List<J4pReadRequest> list = new ArrayList<J4pReadRequest>();
for (ObjectName on : sr.getObjectNames()) {
list.add(new J4pReadRequest(on, "CamelId", "RouteId", "State", "Uptime", "ExchangesTotal", "ExchangesInflight", "ExchangesFailed"));
}
List<J4pReadResponse> lrr = jolokia.execute(list);
for (J4pReadResponse rr : lrr) {
String routeId = rr.getValue("RouteId").toString();
if (filter == null || routeId.matches(filter)) {
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("camelContextName", rr.getValue("CamelId").toString());
row.put("routeId", routeId);
row.put("state", rr.getValue("State").toString());
row.put("uptime", rr.getValue("Uptime").toString());
row.put("exchangesTotal", rr.getValue("ExchangesTotal").toString());
row.put("exchangesInflight", rr.getValue("ExchangesInflight").toString());
row.put("exchangesFailed", rr.getValue("ExchangesFailed").toString());
answer.add(row);
}
}
} else {
List<Map<String, String>> camelContexts = this.getCamelContexts();
for (Map<String, String> row : camelContexts) {
List<Map<String, String>> routes = getRoutes(row.get("name"), filter);
answer.addAll(routes);
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> o1, Map<String, String> o2) {
// group by camel context first, then by route name
String c1 = o1.get("camelContextName");
String c2 = o2.get("camelContextName");
int answer = c1.compareTo(c2);
if (answer == 0) {
// okay from same camel context, then sort by route id
answer = o1.get("routeId").compareTo(o2.get("routeId"));
}
return answer;
}
});
return answer;
}
@Override
public void resetRouteStats(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=*", found.getDomain(), found.getKeyProperty("context"));
J4pSearchResponse sr = jolokia.execute(new J4pSearchRequest(pattern));
List<J4pExecRequest> list = new ArrayList<J4pExecRequest>();
for (ObjectName on : sr.getObjectNames()) {
list.add(new J4pExecRequest(on, "reset(boolean)", true));
}
jolokia.execute(list);
}
}
@Override
public void startRoute(String camelContextName, String routeId) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
jolokia.execute(new J4pExecRequest(on, "start()"));
}
}
@Override
public void stopRoute(String camelContextName, String routeId) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
jolokia.execute(new J4pExecRequest(on, "stop()"));
}
}
@Override
public void suspendRoute(String camelContextName, String routeId) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
jolokia.execute(new J4pExecRequest(on, "suspend()"));
}
}
@Override
public void resumeRoute(String camelContextName, String routeId) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
jolokia.execute(new J4pExecRequest(on, "resume()"));
}
}
@Override
public String getRouteModelAsXml(String routeId, String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "dumpRouteAsXml()"));
if (response != null) {
String xml = response.getValue();
return xml;
}
}
return null;
}
@Override
public String getRouteStatsAsXml(String routeId, String camelContextName, boolean fullStats, boolean includeProcessors) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=routes,name=\"%s\"", found.getDomain(), found.getKeyProperty("context"), routeId);
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "dumpRouteStatsAsXml(boolean,boolean)", fullStats, includeProcessors));
if (response != null) {
String xml = response.getValue();
return xml;
}
}
return null;
}
@Override
public String getRestModelAsXml(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
J4pExecResponse response = jolokia.execute(new J4pExecRequest(found, "dumpRestsAsXml()"));
if (response != null) {
String xml = response.getValue();
return xml;
}
}
return null;
}
@Override
public String getRestApiDocAsJson(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=services,name=DefaultRestRegistry", found.getDomain(), found.getKeyProperty("context"));
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "apiDocAsJson()"));
if (response != null) {
String json = response.getValue();
return json;
}
}
return null;
}
@Override
public List<Map<String, String>> getEndpoints(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=endpoints,*", found.getDomain(), found.getKeyProperty("context"));
J4pSearchResponse sr = jolokia.execute(new J4pSearchRequest(pattern));
List<J4pReadRequest> list = new ArrayList<J4pReadRequest>();
for (ObjectName on : sr.getObjectNames()) {
list.add(new J4pReadRequest(on, "CamelId", "EndpointUri", "State"));
}
List<J4pReadResponse> lrr = jolokia.execute(list);
for (J4pReadResponse rr : lrr) {
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("camelContextName", rr.getValue("CamelId").toString());
row.put("uri", rr.getValue("EndpointUri").toString());
row.put("state", rr.getValue("State").toString());
answer.add(row);
}
}
return answer;
}
@Override
public List<Map<String, String>> getEndpointRuntimeStatistics(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=services,name=DefaultRuntimeEndpointRegistry", found.getDomain(), found.getKeyProperty("context"));
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "endpointStatistics()"));
if (response != null) {
JSONObject data = response.getValue();
for (Object obj : data.values()) {
JSONObject data2 = (JSONObject) obj;
JSONObject service = (JSONObject) data2.values().iterator().next();
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("index", asString(service.get("index")));
row.put("url", asString(service.get("url")));
row.put("routeId", asString(service.get("routeId")));
row.put("direction", asString(service.get("direction")));
row.put("static", asString(service.get("static")));
row.put("dynamic", asString(service.get("dynamic")));
row.put("hits", asString(service.get("hits")));
answer.add(row);
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> endpoint1, Map<String, String> endpoint2) {
// sort by route id
String route1 = endpoint1.get("routeId");
String route2 = endpoint2.get("routeId");
int num = route1.compareTo(route2);
if (num == 0) {
// we want in before out
String dir1 = endpoint1.get("direction");
String dir2 = endpoint2.get("direction");
num = dir1.compareTo(dir2);
}
return num;
}
});
}
return answer;
}
@Override
public List<Map<String, String>> getRestServices(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
String pattern = String.format("%s:context=%s,type=services,name=DefaultRestRegistry", found.getDomain(), found.getKeyProperty("context"));
ObjectName on = ObjectName.getInstance(pattern);
J4pExecResponse response = jolokia.execute(new J4pExecRequest(on, "listRestServices()"));
if (response != null) {
JSONObject data = response.getValue();
if (data != null) {
for (Object obj : data.values()) {
JSONObject data2 = (JSONObject) obj;
JSONObject service = (JSONObject) data2.values().iterator().next();
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("basePath", asString(service.get("basePath")));
row.put("baseUrl", asString(service.get("baseUrl")));
row.put("consumes", asString(service.get("consumes")));
row.put("description", asString(service.get("description")));
row.put("inType", asString(service.get("inType")));
row.put("method", asString(service.get("method")));
row.put("outType", asString(service.get("outType")));
row.put("produces", asString(service.get("produces")));
row.put("routeId", asString(service.get("routeId")));
row.put("state", asString(service.get("state")));
row.put("uriTemplate", asString(service.get("uriTemplate")));
row.put("url", asString(service.get("url")));
answer.add(row);
}
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> service1, Map<String, String> service2) {
String url1 = service1.get("url");
String url2 = service2.get("url");
return url1.compareTo(url2);
}
});
}
return answer;
}
@Override
public String explainEndpointAsJSon(String camelContextName, String uri, boolean allOptions) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
J4pExecResponse response = jolokia.execute(new J4pExecRequest(found, "explainEndpointJson(java.lang.String,boolean)", uri, allOptions));
if (response != null) {
String json = response.getValue();
return json;
}
}
return null;
}
@Override
public String explainEipAsJSon(String camelContextName, String nameOrId, boolean allOptions) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
J4pExecResponse response = jolokia.execute(new J4pExecRequest(found, "explainEipJson(java.lang.String,boolean)", nameOrId, allOptions));
if (response != null) {
String json = response.getValue();
return json;
}
}
return null;
}
@Override
public List<Map<String, String>> listComponents(String camelContextName) throws Exception {
if (jolokia == null) {
throw new IllegalStateException("Need to connect to remote jolokia first");
}
List<Map<String, String>> answer = new ArrayList<Map<String, String>>();
ObjectName found = lookupCamelContext(camelContextName);
if (found != null) {
J4pExecResponse response = jolokia.execute(new J4pExecRequest(found, "listComponents()"));
if (response != null) {
JSONObject data = response.getValue();
for (Object obj : data.values()) {
JSONObject component = (JSONObject) obj;
Map<String, String> row = new LinkedHashMap<String, String>();
row.put("artifactId", asString(component.get("artifactId")));
row.put("title", asString(component.get("title")));
row.put("description", asString(component.get("description")));
row.put("groupId", asString(component.get("groupId")));
row.put("label", asString(component.get("label")));
row.put("name", asString(component.get("name")));
row.put("status", asString(component.get("status")));
row.put("type", asString(component.get("type")));
row.put("version", asString(component.get("version")));
answer.add(row);
}
}
// sort the list
Collections.sort(answer, new Comparator<Map<String, String>>() {
@Override
public int compare(Map<String, String> component1, Map<String, String> component2) {
String name1 = component1.get("name");
String name2 = component2.get("name");
return name1.compareTo(name2);
}
});
}
return answer;
}
private static String asKey(String attributeKey) {
char ch = Character.toLowerCase(attributeKey.charAt(0));
return ch + attributeKey.substring(1);
}
private static String asString(Object basePath) {
if (basePath == null) {
return null;
} else {
return basePath.toString();
}
}
private static String removeLeadingAndEndingQuotes(String s) {
if (s == null || s.isEmpty()) {
return s;
}
String copy = s.trim();
if (copy.startsWith("'") && copy.endsWith("'")) {
return copy.substring(1, copy.length() - 1);
}
if (copy.startsWith("\"") && copy.endsWith("\"")) {
return copy.substring(1, copy.length() - 1);
}
// no quotes, so return as-is
return s;
}
}