/* * Copyright 2015 Cloudius Systems */ package com.scylladb.jmx.api; import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider; import jakarta.json.Json; import jakarta.json.JsonArray; import jakarta.json.JsonObject; import jakarta.json.JsonReader; import jakarta.json.JsonReaderFactory; import jakarta.json.JsonString; import jakarta.ws.rs.ProcessingException; import jakarta.ws.rs.client.Client; import jakarta.ws.rs.client.ClientBuilder; import jakarta.ws.rs.client.Entity; import jakarta.ws.rs.client.Invocation; import jakarta.ws.rs.client.WebTarget; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MultivaluedMap; import jakarta.ws.rs.core.Response; import java.io.StringReader; import java.lang.System.Logger.Level; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.function.BiFunction; import java.util.logging.Logger; import javax.management.openmbean.TabularData; import javax.management.openmbean.TabularDataSupport; import org.glassfish.jersey.client.ClientConfig; import com.scylladb.jmx.api.utils.SnapshotDetailsTabularData; public class APIClient { private Map cache = new HashMap(); private final APIConfig config; private final ClientConfig clientConfig; private final Client client; private JsonReaderFactory factory = Json.createReaderFactory(null); private static final Logger logger = Logger.getLogger(APIClient.class.getName()); public APIClient(APIConfig config) { this.config = config; this.clientConfig = new ClientConfig(); clientConfig.register(new JacksonJsonProvider()); this.client = ClientBuilder.newClient(clientConfig); } private String getCacheKey(String key, MultivaluedMap param, long duration) { if (duration <= 0) { return null; } if (param != null) { StringBuilder sb = new StringBuilder(key); sb.append("?"); for (String k : param.keySet()) { sb.append(k).append('=').append(param.get(k)).append('&'); } return sb.toString(); } return key; } private String getStringFromCache(String key, long duration) { if (key == null) { return null; } CacheEntry value = cache.get(key); return (value != null && value.valid(duration)) ? value.stringValue() : null; } private JsonObject getJsonObjectFromCache(String key, long duration) { if (key == null) { return null; } CacheEntry value = cache.get(key); return (value != null && value.valid(duration)) ? value.jsonObject() : null; } private String getBaseUrl() { return config.getBaseUrl(); } public Invocation.Builder get(String path, MultivaluedMap queryParams) { WebTarget webTarget = client.target(getBaseUrl()).path(path); if (queryParams != null) { for (Entry> qp : queryParams.entrySet()) { for (String e : qp.getValue()) { webTarget = webTarget.queryParam(qp.getKey(), e); } } } return webTarget.request(MediaType.APPLICATION_JSON); } public Invocation.Builder get(String path) { return get(path, null); } public Response post(String path, MultivaluedMap queryParams) { return post(path, queryParams, null); } public Response post(String path, MultivaluedMap queryParams, Object object, String type) { try { Response response = get(path, queryParams).post(Entity.entity(object, type)); if (response.getStatus() != Response.Status.OK.getStatusCode()) { throw getException("Scylla API server HTTP POST to URL '" + path + "' failed", response.readEntity(String.class)); } return response; } catch (ProcessingException e) { throw new IllegalStateException("Unable to connect to Scylla API server: " + e.getMessage()); } } public Response post(String path, MultivaluedMap queryParams, Object object) { return post(path, queryParams, object, MediaType.TEXT_PLAIN); } public void post(String path) { post(path, null); } public IllegalStateException getException(String msg, String json) { JsonReader reader = factory.createReader(new StringReader(json)); JsonObject res = reader.readObject(); return new IllegalStateException(msg + ": " + res.getString("message")); } public String postGetVal(String path, MultivaluedMap queryParams) { return post(path, queryParams).readEntity(String.class); } public int postInt(String path, MultivaluedMap queryParams) { return Integer.parseInt(postGetVal(path, queryParams)); } public int postInt(String path) { return postInt(path, null); } public void delete(String path, MultivaluedMap queryParams) { if (queryParams != null) { get(path, queryParams).delete(); return; } Response response = get(path).delete(); if (response.getStatus() != Response.Status.OK.getStatusCode()) { throw getException("Scylla API server HTTP delete to URL '" + path + "' failed", response.readEntity(String.class)); } } public void delete(String path) { delete(path, null); } public String getRawValue(String string, MultivaluedMap queryParams, long duration) { try { if (string.equals("")) { return ""; } String key = getCacheKey(string, queryParams, duration); String res = getStringFromCache(key, duration); if (res != null) { return res; } Response response = get(string, queryParams).get(Response.class); if (response.getStatus() != Response.Status.OK.getStatusCode()) { // TBD // We are currently not caching errors, // it should be reconsider. throw getException("Scylla API server HTTP GET to URL '" + string + "' failed", response.readEntity(String.class)); } res = response.readEntity(String.class); if (duration > 0) { cache.put(key, new CacheEntry(res)); } return res; } catch (ProcessingException e) { throw new IllegalStateException("Unable to connect to Scylla API server: " + e.getMessage()); } } public String getRawValue(String string, MultivaluedMap queryParams) { return getRawValue(string, queryParams, 0); } public String getRawValue(String string, long duration) { return getRawValue(string, null, duration); } public String getRawValue(String string) { return getRawValue(string, null, 0); } public String getStringValue(String string, MultivaluedMap queryParams) { return getRawValue(string, queryParams).replaceAll("^\"|\"$", ""); } public String getStringValue(String string, MultivaluedMap queryParams, long duration) { return getRawValue(string, queryParams, duration).replaceAll("^\"|\"$", ""); } public String getStringValue(String string) { return getStringValue(string, null); } public JsonReader getReader(String string, MultivaluedMap queryParams) { return factory.createReader(new StringReader(getRawValue(string, queryParams))); } public JsonReader getReader(String string) { return getReader(string, null); } public String[] getStringArrValue(String string) { List val = getListStrValue(string); return val.toArray(new String[val.size()]); } public int getIntValue(String string, MultivaluedMap queryParams) { return Integer.parseInt(getRawValue(string, queryParams)); } public int getIntValue(String string) { return getIntValue(string, null); } public static BiFunction getReader(Class type) { if (type == String.class) { return (c, s) -> type.cast(c.getRawValue(s)); } else if (type == Integer.class) { return (c, s) -> type.cast(c.getIntValue(s)); } else if (type == Double.class) { return (c, s) -> type.cast(c.getDoubleValue(s)); } else if (type == Long.class) { return (c, s) -> type.cast(c.getLongValue(s)); } throw new IllegalArgumentException(type.getName()); } public boolean getBooleanValue(String string) { return Boolean.parseBoolean(getRawValue(string)); } public double getDoubleValue(String string) { return Double.parseDouble(getRawValue(string)); } public List getListStrValue(String string, MultivaluedMap queryParams) { JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); List res = new ArrayList(arr.size()); for (int i = 0; i < arr.size(); i++) { res.add(arr.getString(i)); } reader.close(); return res; } public List getListStrValue(String string) { return getListStrValue(string, null); } public static List listStrFromJArr(JsonArray arr) { List res = new ArrayList(); for (int i = 0; i < arr.size(); i++) { res.add(arr.getString(i)); } return res; } public static Map mapStrFromJArr(JsonArray arr) { Map res = new HashMap(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { res.put(obj.getString("key"), obj.getString("value")); } } return res; } public static String join(String[] arr, String joiner) { String res = ""; if (arr != null) { for (String name : arr) { if (name != null && !name.equals("")) { if (!res.equals("")) { res = res + ","; } res = res + name; } } } return res; } public static String join(String[] arr) { return join(arr, ","); } public static String mapToString(Map mp, String pairJoin, String joiner) { String res = ""; if (mp != null) { for (String name : mp.keySet()) { if (!res.equals("")) { res = res + joiner; } res = res + name + pairJoin + mp.get(name); } } return res; } public static String mapToString(Map mp) { return mapToString(mp, "=", ","); } public static boolean set_query_param(MultivaluedMap queryParams, String key, String value) { if (queryParams != null && key != null && value != null && !value.equals("")) { queryParams.add(key, value); return true; } return false; } public static boolean set_bool_query_param(MultivaluedMap queryParams, String key, boolean value) { if (queryParams != null && key != null && value) { queryParams.add(key, "true"); return true; } return false; } public Map> getMapStringListStrValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map> map = new HashMap>(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { map.put(obj.getString("key"), listStrFromJArr(obj.getJsonArray("value"))); } } reader.close(); return map; } public Map> getMapStringListStrValue(String string) { return getMapStringListStrValue(string, null); } public Map, List> getMapListStrValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map, List> map = new HashMap, List>(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { map.put(listStrFromJArr(obj.getJsonArray("key")), listStrFromJArr(obj.getJsonArray("value"))); } } reader.close(); return map; } public Map, List> getMapListStrValue(String string) { return getMapListStrValue(string, null); } public Set getSetStringValue(String string, MultivaluedMap queryParams) { JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Set res = new HashSet(); for (int i = 0; i < arr.size(); i++) { res.add(arr.getString(i)); } reader.close(); return res; } public Set getSetStringValue(String string) { return getSetStringValue(string, null); } public Map getMapStrValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map map = new LinkedHashMap(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { map.put(obj.getString("key"), obj.getString("value")); } } reader.close(); return map; } public Map getMapStrValue(String string) { return getMapStrValue(string, null); } public Map getReverseMapStrValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map map = new HashMap(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { map.put(obj.getString("value"), obj.getString("key")); } } reader.close(); return map; } public Map getReverseMapStrValue(String string) { return getReverseMapStrValue(string, null); } public List getListInetAddressValue(String string, MultivaluedMap queryParams) { List vals = getListStrValue(string, queryParams); List res = new ArrayList(); for (String val : vals) { try { res.add(InetAddress.getByName(val)); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return res; } public List getListInetAddressValue(String string) { return getListInetAddressValue(string, null); } public Map getMapStringTabularDataValue(String string) { // TODO Auto-generated method stub return null; } private TabularDataSupport getSnapshotData(String key, JsonArray arr) { TabularDataSupport data = new TabularDataSupport(SnapshotDetailsTabularData.TABULAR_TYPE); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("ks") && obj.containsKey("cf")) { SnapshotDetailsTabularData.from(key, obj.getString("ks"), obj.getString("cf"), obj.getJsonNumber("total").longValue(), obj.getJsonNumber("live").longValue(), data); } } return data; } public Map getMapStringSnapshotTabularDataValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map map = new HashMap<>(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); if (obj.containsKey("key") && obj.containsKey("value")) { String key = obj.getString("key"); map.put(key, getSnapshotData(key, obj.getJsonArray("value"))); } } reader.close(); return map; } public long getLongValue(String string) { return Long.parseLong(getRawValue(string)); } public Map getMapInetAddressFloatValue(String string, MultivaluedMap queryParams) { Map res = new HashMap(); JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); JsonObject obj = null; for (int i = 0; i < arr.size(); i++) { try { obj = arr.getJsonObject(i); res.put(InetAddress.getByName(obj.getString("key")), Float.parseFloat(obj.getString("value"))); } catch (UnknownHostException e) { logger.warning("Bad formatted address " + obj.getString("key")); } } return res; } public Map getMapInetAddressFloatValue(String string) { return getMapInetAddressFloatValue(string, null); } public Map getMapStringLongValue(String string, MultivaluedMap queryParams) { Map res = new HashMap(); JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); JsonObject obj = null; for (int i = 0; i < arr.size(); i++) { obj = arr.getJsonObject(i); res.put(obj.getString("key"), obj.getJsonNumber("value").longValue()); } return res; } public Map getMapStringLongValue(String string) { return getMapStringLongValue(string, null); } public long[] getLongArrValue(String string, MultivaluedMap queryParams) { JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); long[] res = new long[arr.size()]; for (int i = 0; i < arr.size(); i++) { res[i] = arr.getJsonNumber(i).longValue(); } reader.close(); return res; } public long[] getLongArrValue(String string) { return getLongArrValue(string, null); } public Map getMapStringIntegerValue(String string, MultivaluedMap queryParams) { Map res = new HashMap(); JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); JsonObject obj = null; for (int i = 0; i < arr.size(); i++) { obj = arr.getJsonObject(i); res.put(obj.getString("key"), obj.getInt("value")); } return res; } public Map getMapStringIntegerValue(String string) { return getMapStringIntegerValue(string, null); } public int[] getIntArrValue(String string, MultivaluedMap queryParams) { JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); int[] res = new int[arr.size()]; for (int i = 0; i < arr.size(); i++) { res[i] = arr.getInt(i); } reader.close(); return res; } public int[] getIntArrValue(String string) { return getIntArrValue(string, null); } public Map getListMapStringLongValue(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map map = new HashMap(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); Iterator it = obj.keySet().iterator(); String key = ""; long val = -1; while (it.hasNext()) { String k = it.next(); if (obj.get(k) instanceof JsonString) { key = obj.getString(k); } else { val = obj.getJsonNumber(k).longValue(); } } if (val > 0 && !key.equals("")) { map.put(key, val); } } reader.close(); return map; } public Map getListMapStringLongValue(String string) { return getListMapStringLongValue(string, null); } public JsonArray getJsonArray(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray res = reader.readArray(); reader.close(); return res; } public JsonArray getJsonArray(String string) { return getJsonArray(string, null); } public List> getListMapStrValue(String string, MultivaluedMap queryParams) { JsonArray arr = getJsonArray(string, queryParams); List> res = new ArrayList>(); for (int i = 0; i < arr.size(); i++) { res.add(mapStrFromJArr(arr.getJsonArray(i))); } return res; } public List> getListMapStrValue(String string) { return getListMapStrValue(string, null); } public TabularData getCQLResult(String string) { // TODO Auto-generated method stub return null; } public JsonObject getJsonObj(String string, MultivaluedMap queryParams, long duration) { if (string.equals("")) { return null; } String key = getCacheKey(string, queryParams, duration); JsonObject res = getJsonObjectFromCache(key, duration); if (res != null) { return res; } JsonReader reader = getReader(string, queryParams); res = reader.readObject(); reader.close(); if (duration > 0) { cache.put(key, new CacheEntry(res)); } return res; } public JsonObject getJsonObj(String string, MultivaluedMap queryParams) { return getJsonObj(string, queryParams, 0); } public long[] getEstimatedHistogramAsLongArrValue(String string, MultivaluedMap queryParams) { JsonObject obj = getJsonObj(string, queryParams); JsonArray arr = obj.getJsonArray("buckets"); if (arr == null) { return new long[0]; } long res[] = new long[arr.size()]; for (int i = 0; i < arr.size(); i++) { res[i] = arr.getJsonNumber(i).longValue(); } return res; } public long[] getEstimatedHistogramAsLongArrValue(String string) { return getEstimatedHistogramAsLongArrValue(string, null); } public Map getMapStringDouble(String string, MultivaluedMap queryParams) { if (string.equals("")) { return null; } JsonReader reader = getReader(string, queryParams); JsonArray arr = reader.readArray(); Map map = new HashMap(); for (int i = 0; i < arr.size(); i++) { JsonObject obj = arr.getJsonObject(i); Iterator it = obj.keySet().iterator(); String key = ""; double val = -1; while (it.hasNext()) { String k = it.next(); if (obj.get(k) instanceof JsonString) { key = obj.getString(k); } else { val = obj.getJsonNumber(k).doubleValue(); } } if (!key.equals("")) { map.put(key, val); } } reader.close(); return map; } public Map getMapStringDouble(String string) { return getMapStringDouble(string, null); } }