diff options
45 files changed, 910 insertions, 827 deletions
diff --git a/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java index 35a95ed3d89..a46abce1dff 100644 --- a/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java +++ b/bundle-plugin-test/integration-test/src/test/java/com/yahoo/container/plugin/BundleTest.java @@ -91,6 +91,7 @@ public class BundleTest { // From SimpleSearcher assertThat(importPackage, containsString("com.yahoo.prelude.hitfield")); + assertThat(importPackage, containsString("org.json")); // From SimpleSearcher2 assertThat(importPackage, containsString("com.yahoo.processing")); diff --git a/bundle-plugin-test/test-bundles/main/pom.xml b/bundle-plugin-test/test-bundles/main/pom.xml index 190e1c9d90f..c9c9ea270eb 100644 --- a/bundle-plugin-test/test-bundles/main/pom.xml +++ b/bundle-plugin-test/test-bundles/main/pom.xml @@ -16,6 +16,11 @@ <packaging>container-plugin</packaging> <dependencies> <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <scope>provided</scope> + </dependency> + <dependency> <groupId>com.yahoo.vespa</groupId> <artifactId>jrt</artifactId> <version>${project.version}</version> diff --git a/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java index ae9644aa010..dddca3f4d59 100644 --- a/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java +++ b/bundle-plugin-test/test-bundles/main/src/main/java/com/yahoo/test/SimpleSearcher.java @@ -8,6 +8,8 @@ import com.yahoo.search.Searcher; import com.yahoo.search.result.Hit; import com.yahoo.search.searchchain.Execution; import com.yahoo.text.BooleanParser; +import org.json.JSONException; +import org.json.JSONObject; /** * A searcher adding a new hit. @@ -17,13 +19,19 @@ import com.yahoo.text.BooleanParser; public class SimpleSearcher extends Searcher { public Result search(Query query,Execution execution) { + try { BooleanParser.parseBoolean("true"); XMLString xmlString = new XMLString("<sampleXmlString/>"); Hit hit = new Hit("Hello world!"); + hit.setField("json", new JSONObject().put("price", 42).toString()); Result result = execution.search(query); result.hits().add(hit); return result; + + } catch (JSONException e) { + throw new RuntimeException(e); + } } } diff --git a/cloud-tenant-base-dependencies-enforcer/pom.xml b/cloud-tenant-base-dependencies-enforcer/pom.xml index 8bb7b75be89..a8655a82860 100644 --- a/cloud-tenant-base-dependencies-enforcer/pom.xml +++ b/cloud-tenant-base-dependencies-enforcer/pom.xml @@ -34,7 +34,7 @@ <junit5.version>5.7.0</junit5.version> <junit5.platform.version>1.7.0</junit5.platform.version> <org.lz4.version>1.7.1</org.lz4.version> - <org.json.version>20090211</org.json.version><!-- TODO Vespa 8: remove as provided dependency --> + <org.json.version>20090211</org.json.version> <slf4j.version>1.7.5</slf4j.version> <tensorflow.version>1.12.0</tensorflow.version> <xml-apis.version>1.4.01</xml-apis.version> diff --git a/container-core/pom.xml b/container-core/pom.xml index 051b572b28f..7c98b524c73 100644 --- a/container-core/pom.xml +++ b/container-core/pom.xml @@ -42,7 +42,6 @@ <scope>test</scope> </dependency> <dependency> - <!-- TODO Vespa 8: stop providing org.json:json --> <groupId>org.json</groupId> <artifactId>json</artifactId> </dependency> diff --git a/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java b/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java index 8c902f88e38..92840cee48f 100644 --- a/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java +++ b/container-core/src/main/java/com/yahoo/container/handler/metrics/HttpHandlerBase.java @@ -1,14 +1,13 @@ // Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.metrics; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; import com.yahoo.container.jdisc.ThreadedHttpRequestHandler; import com.yahoo.restapi.Path; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import java.net.URI; import java.util.List; @@ -27,8 +26,6 @@ import static java.util.logging.Level.WARNING; */ public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - protected HttpHandlerBase(Executor executor) { super(executor); } @@ -52,14 +49,15 @@ public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler { protected JsonResponse resourceListResponse(URI requestUri, List<String> resources) { try { return new JsonResponse(OK, resourceList(requestUri, resources)); - } catch (JsonProcessingException e) { + } catch (JSONException e) { log.log(WARNING, "Bad JSON construction in generated resource list for " + requestUri.getPath(), e); return new ErrorResponse(INTERNAL_SERVER_ERROR, "An error occurred when generating the list of api resources."); } } - private static String resourceList(URI requestUri, List<String> resources) throws JsonProcessingException { + // TODO: Use jackson with a "Resources" class instead of JSONObject + private static String resourceList(URI requestUri, List<String> resources) throws JSONException { int port = requestUri.getPort(); String host = requestUri.getHost(); StringBuilder base = new StringBuilder("http://"); @@ -68,14 +66,13 @@ public abstract class HttpHandlerBase extends ThreadedHttpRequestHandler { base.append(":").append(port); } String uriBase = base.toString(); - ArrayNode linkList = jsonMapper.createArrayNode(); + JSONArray linkList = new JSONArray(); for (String api : resources) { - ObjectNode resource = jsonMapper.createObjectNode(); + JSONObject resource = new JSONObject(); resource.put("url", uriBase + api); - linkList.add(resource); + linkList.put(resource); } - return jsonMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(jsonMapper.createObjectNode().set("resources", linkList)); + return new JSONObject().put("resources", linkList).toString(4); } } diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java index f1ef7894511..d105eaa9d98 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/CoredumpGatherer.java @@ -1,16 +1,17 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.vespa.defaults.Defaults; +import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.time.Instant; +import java.util.Set; import java.util.stream.Stream; /** @@ -18,17 +19,19 @@ import java.util.stream.Stream; */ public class CoredumpGatherer { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final Path COREDUMP_PATH = Path.of(Defaults.getDefaults().underVespaHome("var/crash/processing")); - public static JsonNode gatherCoredumpMetrics(FileWrapper fileWrapper) { + public static JSONObject gatherCoredumpMetrics(FileWrapper fileWrapper) { int coredumps = getNumberOfCoredumps(fileWrapper); - ObjectNode packet = jsonMapper.createObjectNode(); - packet.put("status_code", coredumps == 0 ? 0 : 1); - packet.put("status_msg", coredumps == 0 ? "OK" : String.format("Found %d coredump(s)", coredumps)); - packet.put("timestamp", Instant.now().getEpochSecond()); - packet.put("application", "system-coredumps-processing"); + JSONObject packet = new JSONObject(); + + try { + packet.put("status_code", coredumps == 0 ? 0 : 1); + packet.put("status_msg", coredumps == 0 ? "OK" : String.format("Found %d coredump(s)", coredumps)); + packet.put("timestamp", Instant.now().getEpochSecond()); + packet.put("application", "system-coredumps-processing"); + + } catch (JSONException e) {} return packet; } diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java index 28f99096d84..730f7bc13cd 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/HostLifeGatherer.java @@ -1,9 +1,8 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; +import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.nio.file.Path; @@ -14,11 +13,9 @@ import java.time.Instant; */ public class HostLifeGatherer { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final Path UPTIME_PATH = Path.of("/proc"); - public static JsonNode getHostLifePacket(FileWrapper fileWrapper) { + public static JSONObject getHostLifePacket(FileWrapper fileWrapper) { long upTime; int statusCode = 0; String statusMessage = "OK"; @@ -32,15 +29,19 @@ public class HostLifeGatherer { } - ObjectNode jsonObject = jsonMapper.createObjectNode(); - jsonObject.put("status_code", statusCode); - jsonObject.put("status_msg", statusMessage); - jsonObject.put("timestamp", Instant.now().getEpochSecond()); - jsonObject.put("application", "host_life"); - ObjectNode metrics = jsonMapper.createObjectNode(); - metrics.put("uptime", upTime); - metrics.put("alive", 1); - jsonObject.set("metrics", metrics); + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("status_code", statusCode); + jsonObject.put("status_msg", statusMessage); + jsonObject.put("timestamp", Instant.now().getEpochSecond()); + jsonObject.put("application", "host_life"); + JSONObject metrics = new JSONObject(); + metrics.put("uptime", upTime); + metrics.put("alive", 1); + jsonObject.put("metrics", metrics); + + } catch (JSONException e) {} + return jsonObject; } diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java new file mode 100644 index 00000000000..d22dd9d6f4b --- /dev/null +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/JSONObjectWithLegibleException.java @@ -0,0 +1,87 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.jdisc.state; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Collection; +import java.util.Map; + +/** + * A JSONObject that wraps the checked JSONException in a RuntimeException with a legible error message. + * + * @author gjoranv + */ +class JSONObjectWithLegibleException extends JSONObject { + + @Override + public JSONObject put(String s, boolean b) { + try { + return super.put(s, b); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, b, e), e); + } + } + + @Override + public JSONObject put(String s, double v) { + try { + Double guardedVal = (((Double) v).isNaN() || ((Double) v).isInfinite()) ? + 0.0 : v; + return super.put(s, guardedVal); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, v, e), e); + } + } + + @Override + public JSONObject put(String s, int i) { + try { + return super.put(s, i); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, i, e), e); + } + } + + @Override + public JSONObject put(String s, long l) { + try { + return super.put(s, l); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, l, e), e); + } + } + + @Override + public JSONObject put(String s, Collection collection) { + try { + return super.put(s, collection); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, collection, e), e); + } + } + + @Override + public JSONObject put(String s, Map map) { + try { + return super.put(s, map); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, map, e), e); + } + } + + @Override + public JSONObject put(String s, Object o) { + try { + return super.put(s, o); + } catch (JSONException e) { + throw new RuntimeException(getErrorMessage(s, o, e), e); + } + } + + private String getErrorMessage(String key, Object value, JSONException e) { + return "Trying to add invalid JSON object with key '" + key + + "' and value '" + value + "' - " + e.getMessage(); + } + +} diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java index add69403455..6a06a6362f5 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricGatherer.java @@ -1,7 +1,7 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.databind.JsonNode; +import org.json.JSONObject; import java.util.ArrayList; import java.util.List; @@ -13,9 +13,9 @@ import java.util.List; */ public class MetricGatherer { - static List<JsonNode> getAdditionalMetrics() { + static List<JSONObject> getAdditionalMetrics() { FileWrapper fileWrapper = new FileWrapper(); - List<JsonNode> packetList = new ArrayList<>(); + List<JSONObject> packetList = new ArrayList<>(); packetList.add(CoredumpGatherer.gatherCoredumpMetrics(fileWrapper)); if (System.getProperty("os.name").contains("nux")) packetList.add(HostLifeGatherer.getHostLifePacket(fileWrapper)); diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java index e8d829eafb1..3d3f0e4b677 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/MetricsPacketsHandler.java @@ -1,11 +1,6 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.collections.Tuple2; import com.yahoo.component.provider.ComponentRegistry; @@ -18,6 +13,9 @@ import com.yahoo.jdisc.handler.ResponseDispatch; import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpHeaders; import com.yahoo.metrics.MetricsPresentationConfig; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -46,8 +44,6 @@ import static com.yahoo.container.jdisc.state.StateHandler.getSnapshotPreprocess */ public class MetricsPacketsHandler extends AbstractRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - static final String APPLICATION_KEY = "application"; static final String TIMESTAMP_KEY = "timestamp"; static final String STATUS_CODE_KEY = "status_code"; @@ -101,19 +97,19 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { } String output = jsonToString(getStatusPacket()) + getAllMetricsPackets() + "\n"; return output.getBytes(StandardCharsets.UTF_8); - } catch (JsonProcessingException e) { + } catch (JSONException e) { throw new RuntimeException("Bad JSON construction.", e); } } - private byte[] getMetricsArray() throws JsonProcessingException { - ObjectNode root = jsonMapper.createObjectNode(); - ArrayNode jsonArray = jsonMapper.createArrayNode(); - jsonArray.add(getStatusPacket()); + private byte[] getMetricsArray() throws JSONException { + JSONObject root = new JSONObject(); + JSONArray jsonArray = new JSONArray(); + jsonArray.put(getStatusPacket()); getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis()) - .forEach(jsonArray::add); - MetricGatherer.getAdditionalMetrics().forEach(jsonArray::add); - root.set("metrics", jsonArray); + .forEach(jsonArray::put); + MetricGatherer.getAdditionalMetrics().forEach(jsonArray::put); + root.put("metrics", jsonArray); return jsonToString(root) .getBytes(StandardCharsets.UTF_8); } @@ -121,8 +117,8 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { /** * Exactly one status packet is added to the response. */ - private JsonNode getStatusPacket() { - ObjectNode packet = jsonMapper.createObjectNode(); + private JSONObject getStatusPacket() throws JSONException { + JSONObject packet = new JSONObjectWithLegibleException(); packet.put(APPLICATION_KEY, applicationName); StateMonitor.Status status = monitor.status(); @@ -131,15 +127,14 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { return packet; } - private static String jsonToString(JsonNode jsonObject) throws JsonProcessingException { - return jsonMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(jsonObject); + private String jsonToString(JSONObject jsonObject) throws JSONException { + return jsonObject.toString(4); } - private String getAllMetricsPackets() throws JsonProcessingException { + private String getAllMetricsPackets() throws JSONException { StringBuilder ret = new StringBuilder(); - List<JsonNode> metricsPackets = getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis()); - for (JsonNode packet : metricsPackets) { + List<JSONObject> metricsPackets = getPacketsForSnapshot(getSnapshot(), applicationName, timer.currentTimeMillis()); + for (JSONObject packet : metricsPackets) { ret.append(PACKET_SEPARATOR); // For legibility and parsing in unit tests ret.append(jsonToString(packet)); } @@ -155,16 +150,16 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { } } - private List<JsonNode> getPacketsForSnapshot(MetricSnapshot metricSnapshot, String application, long timestamp) { + private List<JSONObject> getPacketsForSnapshot(MetricSnapshot metricSnapshot, String application, long timestamp) throws JSONException { if (metricSnapshot == null) return Collections.emptyList(); - List<JsonNode> packets = new ArrayList<>(); + List<JSONObject> packets = new ArrayList<>(); for (Map.Entry<MetricDimensions, MetricSet> snapshotEntry : metricSnapshot) { MetricDimensions metricDimensions = snapshotEntry.getKey(); MetricSet metricSet = snapshotEntry.getValue(); - ObjectNode packet = jsonMapper.createObjectNode(); + JSONObjectWithLegibleException packet = new JSONObjectWithLegibleException(); addMetaData(timestamp, application, packet); addDimensions(metricDimensions, packet); addMetrics(metricSet, packet); @@ -173,27 +168,27 @@ public class MetricsPacketsHandler extends AbstractRequestHandler { return packets; } - private void addMetaData(long timestamp, String application, ObjectNode packet) { + private void addMetaData(long timestamp, String application, JSONObjectWithLegibleException packet) { packet.put(APPLICATION_KEY, application); packet.put(TIMESTAMP_KEY, TimeUnit.MILLISECONDS.toSeconds(timestamp)); } - private void addDimensions(MetricDimensions metricDimensions, ObjectNode packet) { + private void addDimensions(MetricDimensions metricDimensions, JSONObjectWithLegibleException packet) throws JSONException { if (metricDimensions == null) return; Iterator<Map.Entry<String, String>> dimensionsIterator = metricDimensions.iterator(); if (dimensionsIterator.hasNext()) { - ObjectNode jsonDim = jsonMapper.createObjectNode(); - packet.set(DIMENSIONS_KEY, jsonDim); + JSONObject jsonDim = new JSONObjectWithLegibleException(); + packet.put(DIMENSIONS_KEY, jsonDim); for (Map.Entry<String, String> dimensionEntry : metricDimensions) { jsonDim.put(dimensionEntry.getKey(), dimensionEntry.getValue()); } } } - private void addMetrics(MetricSet metricSet, ObjectNode packet) { - ObjectNode metrics = jsonMapper.createObjectNode(); - packet.set(METRICS_KEY, metrics); + private void addMetrics(MetricSet metricSet, JSONObjectWithLegibleException packet) throws JSONException { + JSONObjectWithLegibleException metrics = new JSONObjectWithLegibleException(); + packet.put(METRICS_KEY, metrics); for (Map.Entry<String, MetricValue> metric : metricSet) { String name = metric.getKey(); MetricValue value = metric.getValue(); diff --git a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java index 1eb34e15258..b14dc50edcb 100644 --- a/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java +++ b/container-core/src/main/java/com/yahoo/container/jdisc/state/StateHandler.java @@ -1,11 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.collections.Tuple2; import com.yahoo.component.Vtag; @@ -21,16 +16,21 @@ import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpHeaders; import com.yahoo.metrics.MetricsPresentationConfig; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.net.URI; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.io.PrintStream; +import java.io.ByteArrayOutputStream; /** * A handler which returns state (health) information from this container instance: Status, metrics and vespa version. @@ -39,8 +39,6 @@ import java.util.concurrent.TimeUnit; */ public class StateHandler extends AbstractRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - public static final String STATE_API_ROOT = "/state/v1"; private static final String METRICS_PATH = "metrics"; private static final String HISTOGRAMS_PATH = "metrics/histograms"; @@ -126,16 +124,17 @@ public class StateHandler extends AbstractRequestHandler { } base.append(STATE_API_ROOT); String uriBase = base.toString(); - ArrayNode linkList = jsonMapper.createArrayNode(); + JSONArray linkList = new JSONArray(); for (String api : new String[] {METRICS_PATH, CONFIG_GENERATION_PATH, HEALTH_PATH, VERSION_PATH}) { - ObjectNode resource = jsonMapper.createObjectNode(); + JSONObject resource = new JSONObject(); resource.put("url", uriBase + "/" + api); - linkList.add(resource); + linkList.put(resource); } - JsonNode resources = jsonMapper.createObjectNode().set("resources", linkList); - return toPrettyString(resources); - } catch (JsonProcessingException e) { - throw new RuntimeException("Bad JSON construction", e); + return new JSONObjectWithLegibleException() + .put("resources", linkList) + .toString(4).getBytes(StandardCharsets.UTF_8); + } catch (JSONException e) { + throw new RuntimeException("Bad JSON construction.", e); } } @@ -155,31 +154,31 @@ public class StateHandler extends AbstractRequestHandler { private static byte[] buildConfigOutput(ApplicationMetadataConfig config) { try { - return toPrettyString( - jsonMapper.createObjectNode() - .set(CONFIG_GENERATION_PATH, jsonMapper.createObjectNode() - .put("generation", config.generation()) - .set("container", jsonMapper.createObjectNode() - .put("generation", config.generation())))); - } catch (JsonProcessingException e) { + return new JSONObjectWithLegibleException() + .put(CONFIG_GENERATION_PATH, new JSONObjectWithLegibleException() + .put("generation", config.generation()) + .put("container", new JSONObjectWithLegibleException() + .put("generation", config.generation()))) + .toString(4).getBytes(StandardCharsets.UTF_8); + } catch (JSONException e) { throw new RuntimeException("Bad JSON construction.", e); } } private static byte[] buildVersionOutput() { try { - return toPrettyString( - jsonMapper.createObjectNode() - .put("version", Vtag.currentVersion.toString())); - } catch (JsonProcessingException e) { + return new JSONObjectWithLegibleException() + .put("version", Vtag.currentVersion) + .toString(4).getBytes(StandardCharsets.UTF_8); + } catch (JSONException e) { throw new RuntimeException("Bad JSON construction.", e); } } private byte[] buildMetricOutput(String consumer) { try { - return toPrettyString(buildJsonForConsumer(consumer)); - } catch (JsonProcessingException e) { + return buildJsonForConsumer(consumer).toString(4).getBytes(StandardCharsets.UTF_8); + } catch (JSONException e) { throw new RuntimeException("Bad JSON construction.", e); } } @@ -192,11 +191,11 @@ public class StateHandler extends AbstractRequestHandler { return baos.toByteArray(); } - private ObjectNode buildJsonForConsumer(String consumer) { - ObjectNode ret = jsonMapper.createObjectNode(); + private JSONObjectWithLegibleException buildJsonForConsumer(String consumer) throws JSONException { + JSONObjectWithLegibleException ret = new JSONObjectWithLegibleException(); ret.put("time", timer.currentTimeMillis()); - ret.set("status", jsonMapper.createObjectNode().put("code", getStatus().name())); - ret.set(METRICS_PATH, buildJsonForSnapshot(consumer, getSnapshot())); + ret.put("status", new JSONObjectWithLegibleException().put("code", getStatus().name())); + ret.put(METRICS_PATH, buildJsonForSnapshot(consumer, getSnapshot())); return ret; } @@ -213,12 +212,12 @@ public class StateHandler extends AbstractRequestHandler { return monitor.status(); } - private ObjectNode buildJsonForSnapshot(String consumer, MetricSnapshot metricSnapshot) { + private JSONObjectWithLegibleException buildJsonForSnapshot(String consumer, MetricSnapshot metricSnapshot) throws JSONException { if (metricSnapshot == null) { - return jsonMapper.createObjectNode(); + return new JSONObjectWithLegibleException(); } - ObjectNode jsonMetric = jsonMapper.createObjectNode(); - jsonMetric.set("snapshot", jsonMapper.createObjectNode() + JSONObjectWithLegibleException jsonMetric = new JSONObjectWithLegibleException(); + jsonMetric.put("snapshot", new JSONObjectWithLegibleException() .put("from", metricSnapshot.getFromTime(TimeUnit.MILLISECONDS) / 1000.0) .put("to", metricSnapshot.getToTime(TimeUnit.MILLISECONDS) / 1000.0)); @@ -226,16 +225,16 @@ public class StateHandler extends AbstractRequestHandler { long periodInMillis = metricSnapshot.getToTime(TimeUnit.MILLISECONDS) - metricSnapshot.getFromTime(TimeUnit.MILLISECONDS); for (Tuple tuple : collapseMetrics(metricSnapshot, consumer)) { - ObjectNode jsonTuple = jsonMapper.createObjectNode(); + JSONObjectWithLegibleException jsonTuple = new JSONObjectWithLegibleException(); jsonTuple.put("name", tuple.key); if (tuple.val instanceof CountMetric) { CountMetric count = (CountMetric)tuple.val; - jsonTuple.set("values", jsonMapper.createObjectNode() + jsonTuple.put("values", new JSONObjectWithLegibleException() .put("count", count.getCount()) .put("rate", (count.getCount() * 1000.0) / periodInMillis)); } else if (tuple.val instanceof GaugeMetric) { GaugeMetric gauge = (GaugeMetric) tuple.val; - ObjectNode valueFields = jsonMapper.createObjectNode(); + JSONObjectWithLegibleException valueFields = new JSONObjectWithLegibleException(); valueFields.put("average", gauge.getAverage()) .put("sum", gauge.getSum()) .put("count", gauge.getCount()) @@ -248,27 +247,22 @@ public class StateHandler extends AbstractRequestHandler { valueFields.put(prefixAndValue.first + "percentile", prefixAndValue.second.doubleValue()); } } - jsonTuple.set("values", valueFields); + jsonTuple.put("values", valueFields); } else { throw new UnsupportedOperationException(tuple.val.getClass().getName()); } if (tuple.dim != null) { Iterator<Map.Entry<String, String>> it = tuple.dim.iterator(); if (it.hasNext() && includeDimensions) { - ObjectNode jsonDim = jsonMapper.createObjectNode(); + JSONObjectWithLegibleException jsonDim = new JSONObjectWithLegibleException(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); jsonDim.put(entry.getKey(), entry.getValue()); } - jsonTuple.set("dimensions", jsonDim); + jsonTuple.put("dimensions", jsonDim); } } - ArrayNode values = (ArrayNode) jsonMetric.get("values"); - if (values == null) { - values = jsonMapper.createArrayNode(); - jsonMetric.set("values", values); - } - values.add(jsonTuple); + jsonMetric.append("values", jsonTuple); } return jsonMetric; } @@ -322,12 +316,6 @@ public class StateHandler extends AbstractRequestHandler { return metrics; } - private static byte[] toPrettyString(JsonNode resources) throws JsonProcessingException { - return jsonMapper.writerWithDefaultPrettyPrinter() - .writeValueAsString(resources) - .getBytes(); - } - static class Tuple { final MetricDimensions dim; diff --git a/container-core/src/main/java/org/json/package-info.java b/container-core/src/main/java/org/json/package-info.java index 7ca9fe91e31..44630ad235a 100644 --- a/container-core/src/main/java/org/json/package-info.java +++ b/container-core/src/main/java/org/json/package-info.java @@ -1,5 +1,5 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. @ExportPackage package org.json; -// TODO Vespa 8: stop providing org.json + import com.yahoo.osgi.annotation.ExportPackage; diff --git a/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java b/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java index ca4bec30322..9020ed91026 100644 --- a/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java +++ b/container-core/src/test/java/com/yahoo/container/handler/metrics/MetricsV2HandlerTest.java @@ -1,18 +1,17 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.metrics; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.github.tomakehurst.wiremock.junit.WireMockRule; import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.concurrent.Executors; @@ -35,8 +34,6 @@ import static org.junit.Assert.fail; */ public class MetricsV2HandlerTest { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String URI_BASE = "http://localhost"; private static final String V2_URI = URI_BASE + V2_PATH; @@ -82,29 +79,29 @@ public class MetricsV2HandlerTest { @Test public void v2_response_contains_values_uri() throws Exception { String response = testDriver.sendRequest(V2_URI).readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("resources")); - ArrayNode resources = (ArrayNode) root.get("resources"); - assertEquals(1, resources.size()); + JSONArray resources = root.getJSONArray("resources"); + assertEquals(1, resources.length()); - JsonNode valuesUri = resources.get(0); - assertEquals(VALUES_URI, valuesUri.get("url").textValue()); + JSONObject valuesUri = resources.getJSONObject(0); + assertEquals(VALUES_URI, valuesUri.getString("url")); } @Ignore @Test - public void visually_inspect_values_response() { - JsonNode responseJson = getResponseAsJson(null); - System.out.println(responseJson); + public void visually_inspect_values_response() throws Exception { + JSONObject responseJson = getResponseAsJson(null); + System.out.println(responseJson.toString(4)); } @Test public void invalid_path_yields_error_response() throws Exception { String response = testDriver.sendRequest(V2_URI + "/invalid").readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("error")); - assertTrue(root.get("error" ).textValue().startsWith("No content")); + assertTrue(root.getString("error" ).startsWith("No content")); } @Test @@ -114,23 +111,23 @@ public class MetricsV2HandlerTest { } @Test - public void consumer_is_propagated_to_metrics_proxy_api() { - JsonNode responseJson = getResponseAsJson(CUSTOM_CONSUMER); + public void consumer_is_propagated_to_metrics_proxy_api() throws JSONException { + JSONObject responseJson = getResponseAsJson(CUSTOM_CONSUMER); - JsonNode firstNodeMetricsValues = - responseJson.get("nodes").get(0) - .get("node") - .get("metrics").get(0) - .get("values"); + JSONObject firstNodeMetricsValues = + responseJson.getJSONArray("nodes").getJSONObject(0) + .getJSONObject("node") + .getJSONArray("metrics").getJSONObject(0) + .getJSONObject("values"); assertTrue(firstNodeMetricsValues.has(REPLACED_CPU_METRIC)); } - private JsonNode getResponseAsJson(String consumer) { + private JSONObject getResponseAsJson(String consumer) { String response = testDriver.sendRequest(VALUES_URI + consumerQuery(consumer)).readAll(); try { - return jsonMapper.readTree(response); - } catch (IOException e) { + return new JSONObject(response); + } catch (JSONException e) { fail("Failed to create json object: " + e.getMessage()); throw new RuntimeException(e); } diff --git a/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java b/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java index 9ffce6d1c28..a0e8c131c2b 100644 --- a/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java +++ b/container-core/src/test/java/com/yahoo/container/handler/metrics/PrometheusV1HandlerTest.java @@ -1,11 +1,15 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.metrics; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.github.tomakehurst.wiremock.junit.WireMockRule; import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.stream.Collectors; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; @@ -22,14 +26,13 @@ import static com.yahoo.container.handler.metrics.MetricsV2Handler.consumerQuery import static com.yahoo.container.handler.metrics.MetricsV2HandlerTest.getFileContents; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; /** * @author gjoranv */ public class PrometheusV1HandlerTest { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String URI_BASE = "http://localhost"; private static final String V1_URI = URI_BASE + PrometheusV1Handler.V1_PATH; @@ -76,14 +79,14 @@ public class PrometheusV1HandlerTest { @Test public void v1_response_contains_values_uri() throws Exception { String response = testDriver.sendRequest(V1_URI).readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("resources")); - ArrayNode resources = (ArrayNode) root.get("resources"); - assertEquals(1, resources.size()); + JSONArray resources = root.getJSONArray("resources"); + assertEquals(1, resources.length()); - JsonNode valuesUri = resources.get(0); - assertEquals(VALUES_URI, valuesUri.get("url").asText()); + JSONObject valuesUri = resources.getJSONObject(0); + assertEquals(VALUES_URI, valuesUri.getString("url")); } @Ignore @@ -96,9 +99,9 @@ public class PrometheusV1HandlerTest { @Test public void invalid_path_yields_error_response() throws Exception { String response = testDriver.sendRequest(V1_URI + "/invalid").readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("error")); - assertTrue(root.get("error" ).textValue().startsWith("No content")); + assertTrue(root.getString("error" ).startsWith("No content")); } @Test diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java index 8a3d0e837c5..c1f7d790fa5 100644 --- a/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java +++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/CoredumpGathererTest.java @@ -1,7 +1,8 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.databind.JsonNode; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import java.nio.file.Path; @@ -16,12 +17,12 @@ import static org.junit.Assert.assertEquals; public class CoredumpGathererTest { @Test - public void finds_one_coredump() { - JsonNode packet = CoredumpGatherer.gatherCoredumpMetrics(new MockFileWrapper()); + public void finds_one_coredump() throws JSONException { + JSONObject packet = CoredumpGatherer.gatherCoredumpMetrics(new MockFileWrapper()); - assertEquals("system-coredumps-processing", packet.get("application").textValue()); - assertEquals(1, packet.get("status_code").intValue()); - assertEquals("Found 1 coredump(s)", packet.get("status_msg").textValue()); + assertEquals("system-coredumps-processing", packet.getString("application")); + assertEquals(1, packet.getInt("status_code")); + assertEquals("Found 1 coredump(s)", packet.getString("status_msg")); } diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java index 12852c9d54c..d025b9662d2 100644 --- a/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java +++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/HostLifeGathererTest.java @@ -1,7 +1,8 @@ // Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.jdisc.state; -import com.fasterxml.jackson.databind.JsonNode; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import java.nio.file.Path; @@ -15,15 +16,15 @@ import static org.junit.Assert.assertEquals; public class HostLifeGathererTest { @Test - public void host_is_alive() { - JsonNode packet = HostLifeGatherer.getHostLifePacket(new MockFileWrapper()); - JsonNode metrics = packet.get("metrics"); - assertEquals("host_life", packet.get("application").textValue()); - assertEquals(0, packet.get("status_code").intValue()); - assertEquals("OK", packet.get("status_msg").textValue()); - - assertEquals(123L, metrics.get("uptime").longValue()); - assertEquals(1, metrics.get("alive").intValue()); + public void host_is_alive() throws JSONException { + JSONObject packet = HostLifeGatherer.getHostLifePacket(new MockFileWrapper()); + JSONObject metrics = packet.getJSONObject("metrics"); + assertEquals("host_life", packet.getString("application")); + assertEquals(0, packet.getInt("status_code")); + assertEquals("OK", packet.getString("status_msg")); + + assertEquals(123l, metrics.getLong("uptime")); + assertEquals(1, metrics.getInt("alive")); } diff --git a/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java b/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java index 385eb627427..1258ecdc46f 100644 --- a/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java +++ b/container-core/src/test/java/com/yahoo/container/jdisc/state/StateHandlerTest.java @@ -98,38 +98,37 @@ public class StateHandlerTest extends StateHandlerTestBase { snapshotProvider.setSnapshot(snapshot); advanceToNextSnapshot(); assertEquals("{\n" + - " \"time\" : 300000,\n" + - " \"status\" : {\n" + - " \"code\" : \"up\"\n" + - " },\n" + - " \"metrics\" : {\n" + - " \"snapshot\" : {\n" + - " \"from\" : 0.0,\n" + - " \"to\" : 300.0\n" + - " },\n" + - " \"values\" : [ {\n" + - " \"name\" : \"foo\",\n" + - " \"values\" : {\n" + - " \"count\" : 1,\n" + - " \"rate\" : 0.0033333333333333335\n" + - " }\n" + - " }, {\n" + - " \"name\" : \"bar\",\n" + - " \"values\" : {\n" + - " \"average\" : 3.5,\n" + - " \"sum\" : 14.0,\n" + - " \"count\" : 4,\n" + - " \"last\" : 5.0,\n" + - " \"max\" : 5.0,\n" + - " \"min\" : 2.0,\n" + - " \"rate\" : 0.013333333333333334\n" + - " },\n" + - " \"dimensions\" : {\n" + - " \"component\" : \"test\"\n" + - " }\n" + - " } ]\n" + - " }\n" + - "}", + " \"metrics\": {\n" + + " \"snapshot\": {\n" + + " \"from\": 0,\n" + + " \"to\": 300\n" + + " },\n" + + " \"values\": [\n" + + " {\n" + + " \"name\": \"foo\",\n" + + " \"values\": {\n" + + " \"count\": 1,\n" + + " \"rate\": 0.0033333333333333335\n" + + " }\n" + + " },\n" + + " {\n" + + " \"dimensions\": {\"component\": \"test\"},\n" + + " \"name\": \"bar\",\n" + + " \"values\": {\n" + + " \"average\": 3.5,\n" + + " \"count\": 4,\n" + + " \"last\": 5,\n" + + " \"max\": 5,\n" + + " \"min\": 2,\n" + + " \"rate\": 0.013333333333333334,\n" + + " \"sum\": 14\n" + + " }\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"status\": {\"code\": \"up\"},\n" + + " \"time\": 300000\n" + + "}", requestAsString(V1_URI + "all")); } diff --git a/container-dependency-versions/pom.xml b/container-dependency-versions/pom.xml index 08d6e0103bf..8691d9a7ffb 100644 --- a/container-dependency-versions/pom.xml +++ b/container-dependency-versions/pom.xml @@ -313,7 +313,7 @@ <artifactId>javassist</artifactId> <version>${javassist.version}</version> </dependency> - <dependency> <!-- TODO Vespa 8: remove as provided dependency --> + <dependency> <!-- TODO Vespa 8: upgrade to newest version. Consider removing as provided dependency --> <groupId>org.json</groupId> <artifactId>json</artifactId> <version>${org.json.version}</version> diff --git a/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java b/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java index df7cacdc768..709441999d0 100644 --- a/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java +++ b/container-disc/src/main/java/com/yahoo/container/usability/BindingsOverviewHandler.java @@ -1,13 +1,9 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.usability; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.component.ComponentId; +import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.Container; import com.yahoo.container.jdisc.JdiscBindingsConfig; import com.yahoo.jdisc.handler.AbstractRequestHandler; @@ -19,11 +15,16 @@ import com.yahoo.jdisc.handler.ResponseDispatch; import com.yahoo.jdisc.handler.ResponseHandler; import com.yahoo.jdisc.http.HttpRequest; import com.yahoo.jdisc.http.HttpRequest.Method; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -32,8 +33,6 @@ import java.util.Map; */ public class BindingsOverviewHandler extends AbstractRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private final JdiscBindingsConfig bindingsConfig; @Inject @@ -43,7 +42,7 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { @Override public ContentChannel handleRequest(com.yahoo.jdisc.Request request, ResponseHandler handler) { - JsonNode json; + JSONObject json; int statusToReturn; if (request instanceof HttpRequest && ((HttpRequest) request).getMethod() != Method.GET) { @@ -64,9 +63,7 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { }.connect(handler)); try { - writer.write(jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(json)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); + writer.write(json.toString()); } finally { writer.close(); } @@ -74,58 +71,63 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { return new IgnoredContent(); } - private static JsonNode errorMessageInJson() { - ObjectNode error = jsonMapper.createObjectNode(); - error.put("error", "This API, " - + BindingsOverviewHandler.class.getSimpleName() - + ", only supports HTTP GET." - + " You are probably looking for another API/path."); + private JSONObject errorMessageInJson() { + JSONObject error = new JSONObject(); + try { + error.put("error", "This API, " + + this.getClass().getSimpleName() + + ", only supports HTTP GET." + + " You are probably looking for another API/path."); + } catch (org.json.JSONException e) { + // just ignore it + } return error; } - static ArrayNode renderRequestHandlers(JdiscBindingsConfig bindingsConfig, + static JSONArray renderRequestHandlers(JdiscBindingsConfig bindingsConfig, Map<ComponentId, ? extends RequestHandler> handlersById) { - ArrayNode ret = jsonMapper.createArrayNode(); + JSONArray ret = new JSONArray(); for (Map.Entry<ComponentId, ? extends RequestHandler> handlerEntry : handlersById.entrySet()) { String id = handlerEntry.getKey().stringValue(); RequestHandler handler = handlerEntry.getValue(); - ObjectNode handlerJson = renderComponent(handler, handlerEntry.getKey()); + JSONObject handlerJson = renderComponent(handler, handlerEntry.getKey()); addBindings(bindingsConfig, id, handlerJson); - ret.add(handlerJson); + ret.put(handlerJson); } return ret; } - private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, ObjectNode handlerJson) { + private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, JSONObject handlerJson) { List<String> serverBindings = new ArrayList<>(); JdiscBindingsConfig.Handlers handlerConfig = bindingsConfig.handlers(id); if (handlerConfig != null) { serverBindings = handlerConfig.serverBindings(); } - handlerJson.set("serverBindings", renderBindings(serverBindings)); + putJson(handlerJson, "serverBindings", renderBindings(serverBindings)); } - private static JsonNode renderBindings(List<String> bindings) { - ArrayNode array = jsonMapper.createArrayNode(); + private static JSONArray renderBindings(List<String> bindings) { + JSONArray array = new JSONArray(); for (String binding : bindings) - array.add(binding); + array.put(binding); return array; } - private static ObjectNode renderComponent(Object component, ComponentId id) { - ObjectNode jc = jsonMapper.createObjectNode(); - jc.put("id", id.stringValue()); + private static JSONObject renderComponent(Object component, ComponentId id) { + JSONObject jc = new JSONObject(); + putJson(jc, "id", id.stringValue()); addBundleInfo(jc, component); return jc; } - private static void addBundleInfo(ObjectNode jsonObject, Object component) { + private static void addBundleInfo(JSONObject jsonObject, Object component) { BundleInfo bundleInfo = bundleInfo(component); - jsonObject.put("class", bundleInfo.className); - jsonObject.put("bundle", bundleInfo.bundleName); + putJson(jsonObject, "class", bundleInfo.className); + putJson(jsonObject, "bundle", bundleInfo.bundleName); + } private static BundleInfo bundleInfo(Object component) { @@ -141,6 +143,15 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { } } + private static void putJson(JSONObject json, String key, Object value) { + try { + json.put(key, value); + } catch (JSONException e) { + // The original JSONException lacks key-value info. + throw new RuntimeException("Trying to add invalid JSON object with key '" + key + "' and value '" + value + "' - " + e.getMessage(), e); + } + } + static final class BundleInfo { public final String className; @@ -161,10 +172,10 @@ public class BindingsOverviewHandler extends AbstractRequestHandler { this.bindingsConfig = bindingsConfig; } - public JsonNode render() { - ObjectNode root = jsonMapper.createObjectNode(); + public JSONObject render() { + JSONObject root = new JSONObject(); - root.set("handlers", + putJson(root, "handlers", renderRequestHandlers(bindingsConfig, Container.get().getRequestHandlerRegistry().allComponentsById())); return root; diff --git a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java index 943eef1e0bf..57c5e768cfb 100644 --- a/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java +++ b/container-search-and-docproc/src/main/java/com/yahoo/container/handler/observability/ApplicationStatusHandler.java @@ -1,11 +1,6 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.handler.observability; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; import com.yahoo.component.AbstractComponent; import com.yahoo.component.ComponentId; @@ -34,11 +29,15 @@ import com.yahoo.processing.execution.chain.ChainRegistry; import com.yahoo.processing.handler.ProcessingHandler; import com.yahoo.search.handler.SearchHandler; import com.yahoo.search.searchchain.SearchChainRegistry; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.Iterator; import java.util.List; @@ -52,13 +51,11 @@ import java.util.Map; */ public class ApplicationStatusHandler extends AbstractRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - - private final JsonNode applicationJson; - private final JsonNode clientsJson; - private final JsonNode serversJson; - private final JsonNode requestFiltersJson; - private final JsonNode responseFiltersJson; + private final JSONObject applicationJson; + private final JSONArray clientsJson; + private final JSONArray serversJson; + private final JSONArray requestFiltersJson; + private final JSONArray responseFiltersJson; private final JdiscBindingsConfig bindingsConfig; @Inject @@ -81,7 +78,7 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { @Override public ContentChannel handleRequest(com.yahoo.jdisc.Request request, ResponseHandler handler) { - JsonNode json = new StatusResponse(applicationJson, clientsJson, serversJson, + JSONObject json = new StatusResponse(applicationJson, clientsJson, serversJson, requestFiltersJson, responseFiltersJson, bindingsConfig) .render(); @@ -94,66 +91,62 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } }.connect(handler)); - try { - writer.write(jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsBytes(json)); - } catch (JsonProcessingException e) { - throw new RuntimeException("Invalid JSON: " + e.getMessage(), e); - } + writer.write(json.toString()); writer.close(); return new IgnoredContent(); } - static JsonNode renderApplicationConfigs(ApplicationMetadataConfig metaConfig, + static JSONObject renderApplicationConfigs(ApplicationMetadataConfig metaConfig, ApplicationUserdataConfig userConfig) { - ObjectNode vespa = jsonMapper.createObjectNode(); - vespa.put("version", Vtag.currentVersion.toString()); - - ObjectNode meta = jsonMapper.createObjectNode(); - meta.put("name", metaConfig.name()); - meta.put("user", metaConfig.user()); - meta.put("path", metaConfig.path()); - meta.put("generation", metaConfig.generation()); - meta.put("timestamp", metaConfig.timestamp()); - meta.put("date", new Date(metaConfig.timestamp()).toString()); - meta.put("checksum", metaConfig.checksum()); - - ObjectNode user = jsonMapper.createObjectNode(); - user.put("version", userConfig.version()); - - ObjectNode application = jsonMapper.createObjectNode(); - application.set("vespa", vespa); - application.set("meta", meta); - application.set("user", user); + JSONObject vespa = new JSONObject(); + putJson(vespa, "version", Vtag.currentVersion); + + JSONObject meta = new JSONObject(); + putJson(meta, "name", metaConfig.name()); + putJson(meta, "user", metaConfig.user()); + putJson(meta, "path", metaConfig.path()); + putJson(meta, "generation", metaConfig.generation()); + putJson(meta, "timestamp", metaConfig.timestamp()); + putJson(meta, "date", new Date(metaConfig.timestamp()).toString()); + putJson(meta, "checksum", metaConfig.checksum()); + + JSONObject user = new JSONObject(); + putJson(user, "version", userConfig.version()); + + JSONObject application = new JSONObject(); + putJson(application, "vespa", vespa); + putJson(application, "meta", meta); + putJson(application, "user", user); return application; } - static JsonNode renderObjectComponents(Map<ComponentId, ?> componentsById) { - ArrayNode ret = jsonMapper.createArrayNode(); + static JSONArray renderObjectComponents(Map<ComponentId, ?> componentsById) { + JSONArray ret = new JSONArray(); for (Map.Entry<ComponentId, ?> componentEntry : componentsById.entrySet()) { - JsonNode jc = renderComponent(componentEntry.getValue(), componentEntry.getKey()); - ret.add(jc); + JSONObject jc = renderComponent(componentEntry.getValue(), componentEntry.getKey()); + ret.put(jc); } return ret; } - static JsonNode renderRequestHandlers(JdiscBindingsConfig bindingsConfig, + static JSONArray renderRequestHandlers(JdiscBindingsConfig bindingsConfig, Map<ComponentId, ? extends RequestHandler> handlersById) { - ArrayNode ret = jsonMapper.createArrayNode(); + JSONArray ret = new JSONArray(); for (Map.Entry<ComponentId, ? extends RequestHandler> handlerEntry : handlersById.entrySet()) { String id = handlerEntry.getKey().stringValue(); RequestHandler handler = handlerEntry.getValue(); - ObjectNode handlerJson = renderComponent(handler, handlerEntry.getKey()); + JSONObject handlerJson = renderComponent(handler, handlerEntry.getKey()); addBindings(bindingsConfig, id, handlerJson); - ret.add(handlerJson); + ret.put(handlerJson); } return ret; } - private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, ObjectNode handlerJson) { + private static void addBindings(JdiscBindingsConfig bindingsConfig, String id, JSONObject handlerJson) { List<String> serverBindings = new ArrayList<>(); List<String> clientBindings = new ArrayList<>(); @@ -162,40 +155,40 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { serverBindings = handlerConfig.serverBindings(); clientBindings = handlerConfig.clientBindings(); } - handlerJson.set("serverBindings", renderBindings(serverBindings)); - handlerJson.set("clientBindings", renderBindings(clientBindings)); + putJson(handlerJson, "serverBindings", renderBindings(serverBindings)); + putJson(handlerJson, "clientBindings", renderBindings(clientBindings)); } - private static JsonNode renderBindings(List<String> bindings) { - ArrayNode ret = jsonMapper.createArrayNode(); + private static JSONArray renderBindings(List<String> bindings) { + JSONArray ret = new JSONArray(); for (String binding : bindings) - ret.add(binding); + ret.put(binding); return ret; } - private static JsonNode renderAbstractComponents(List<? extends AbstractComponent> components) { - ArrayNode ret = jsonMapper.createArrayNode(); + private static JSONArray renderAbstractComponents(List<? extends AbstractComponent> components) { + JSONArray ret = new JSONArray(); for (AbstractComponent c : components) { - JsonNode jc = renderComponent(c, c.getId()); - ret.add(jc); + JSONObject jc = renderComponent(c, c.getId()); + ret.put(jc); } return ret; } - private static ObjectNode renderComponent(Object component, ComponentId id) { - ObjectNode jc = jsonMapper.createObjectNode(); - jc.put("id", id.stringValue()); + private static JSONObject renderComponent(Object component, ComponentId id) { + JSONObject jc = new JSONObject(); + putJson(jc, "id", id.stringValue()); addBundleInfo(jc, component); return jc; } - private static void addBundleInfo(ObjectNode jsonObject, Object component) { + private static void addBundleInfo(JSONObject jsonObject, Object component) { BundleInfo bundleInfo = bundleInfo(component); - jsonObject.put("class", bundleInfo.className); - jsonObject.put("bundle", bundleInfo.bundleName); + putJson(jsonObject, "class", bundleInfo.className); + putJson(jsonObject, "bundle", bundleInfo.bundleName); } @@ -212,6 +205,15 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } } + private static void putJson(JSONObject json, String key, Object value) { + try { + json.put(key, value); + } catch (JSONException e) { + // The original JSONException lacks key-value info. + throw new RuntimeException("Trying to add invalid JSON object with key '" + key + "' and value '" + value + "' - " + e.getMessage(), e); + } + } + static final class BundleInfo { public final String className; public final String bundleName; @@ -222,18 +224,18 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } static final class StatusResponse { - private final JsonNode applicationJson; - private final JsonNode clientsJson; - private final JsonNode serversJson; - private final JsonNode requestFiltersJson; - private final JsonNode responseFiltersJson; + private final JSONObject applicationJson; + private final JSONArray clientsJson; + private final JSONArray serversJson; + private final JSONArray requestFiltersJson; + private final JSONArray responseFiltersJson; private final JdiscBindingsConfig bindingsConfig; - StatusResponse(JsonNode applicationJson, - JsonNode clientsJson, - JsonNode serversJson, - JsonNode requestFiltersJson, - JsonNode responseFiltersJson, + StatusResponse(JSONObject applicationJson, + JSONArray clientsJson, + JSONArray serversJson, + JSONArray requestFiltersJson, + JSONArray responseFiltersJson, JdiscBindingsConfig bindingsConfig) { this.applicationJson = applicationJson; this.clientsJson = clientsJson; @@ -243,52 +245,52 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { this.bindingsConfig = bindingsConfig; } - public JsonNode render() { - ObjectNode root = jsonMapper.createObjectNode(); + public JSONObject render() { + JSONObject root = new JSONObject(); - root.set("application", applicationJson); - root.set("abstractComponents", + putJson(root, "application", applicationJson); + putJson(root, "abstractComponents", renderAbstractComponents(Container.get().getComponentRegistry().allComponents())); - root.set("handlers", + putJson(root, "handlers", renderRequestHandlers(bindingsConfig, Container.get().getRequestHandlerRegistry().allComponentsById())); - root.set("clients", clientsJson); - root.set("servers", serversJson); - root.set("httpRequestFilters", requestFiltersJson); - root.set("httpResponseFilters", responseFiltersJson); + putJson(root, "clients", clientsJson); + putJson(root, "servers", serversJson); + putJson(root, "httpRequestFilters", requestFiltersJson); + putJson(root, "httpResponseFilters", responseFiltersJson); - root.set("searchChains", renderSearchChains(Container.get())); - root.set("docprocChains", renderDocprocChains(Container.get())); - root.set("processingChains", renderProcessingChains(Container.get())); + putJson(root, "searchChains", renderSearchChains(Container.get())); + putJson(root, "docprocChains", renderDocprocChains(Container.get())); + putJson(root, "processingChains", renderProcessingChains(Container.get())); return root; } - private static JsonNode renderSearchChains(Container container) { + private static JSONObject renderSearchChains(Container container) { for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof SearchHandler) { SearchChainRegistry scReg = ((SearchHandler) h).getSearchChainRegistry(); return renderChains(scReg); } } - return jsonMapper.createObjectNode(); + return new JSONObject(); } - private static JsonNode renderDocprocChains(Container container) { - ObjectNode ret = jsonMapper.createObjectNode(); + private static JSONObject renderDocprocChains(Container container) { + JSONObject ret = new JSONObject(); for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof DocumentProcessingHandler) { ComponentRegistry<DocprocService> registry = ((DocumentProcessingHandler) h).getDocprocServiceRegistry(); for (DocprocService service : registry.allComponents()) { - ret.set(service.getId().stringValue(), renderCalls(service.getCallStack().iterator())); + putJson(ret, service.getId().stringValue(), renderCalls(service.getCallStack().iterator())); } } } return ret; } - private static JsonNode renderProcessingChains(Container container) { - JsonNode ret = jsonMapper.createObjectNode(); + private static JSONObject renderProcessingChains(Container container) { + JSONObject ret = new JSONObject(); for (RequestHandler h : container.getRequestHandlerRegistry().allComponents()) { if (h instanceof ProcessingHandler) { ChainRegistry<Processor> registry = ((ProcessingHandler) h).getChainRegistry(); @@ -299,20 +301,20 @@ public class ApplicationStatusHandler extends AbstractRequestHandler { } // Note the generic param here! The key to make this work is '? extends Chain', but why? - static JsonNode renderChains(ComponentRegistry<? extends Chain<?>> chains) { - ObjectNode ret = jsonMapper.createObjectNode(); + static JSONObject renderChains(ComponentRegistry<? extends Chain<?>> chains) { + JSONObject ret = new JSONObject(); for (Chain<?> chain : chains.allComponents()) { - ret.set(chain.getId().stringValue(), renderAbstractComponents(chain.components())); + putJson(ret, chain.getId().stringValue(), renderAbstractComponents(chain.components())); } return ret; } - private static JsonNode renderCalls(Iterator<Call> components) { - ArrayNode ret = jsonMapper.createArrayNode(); + private static JSONArray renderCalls(Iterator<Call> components) { + JSONArray ret = new JSONArray(); while (components.hasNext()) { Call c = components.next(); - JsonNode jc = renderComponent(c.getDocumentProcessor(), c.getDocumentProcessor().getId()); - ret.add(jc); + JSONObject jc = renderComponent(c.getDocumentProcessor(), c.getDocumentProcessor().getId()); + ret.put(jc); } return ret; } diff --git a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java index 3132f3744c9..9ddcc7a7e69 100644 --- a/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java +++ b/container-search-gui/src/main/java/com/yahoo/search/query/gui/GUIHandler.java @@ -1,10 +1,8 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.query.gui; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.inject.Inject; + import com.yahoo.container.QrSearchersConfig; import com.yahoo.container.jdisc.HttpRequest; import com.yahoo.container.jdisc.HttpResponse; @@ -13,7 +11,6 @@ import com.yahoo.prelude.IndexModel; import com.yahoo.prelude.querytransform.RecallSearcher; import com.yahoo.restapi.Path; import com.yahoo.search.Query; -import com.yahoo.search.config.IndexInfoConfig; import com.yahoo.search.query.Model; import com.yahoo.search.query.Presentation; import com.yahoo.search.query.Ranking; @@ -22,12 +19,19 @@ import com.yahoo.search.query.ranking.MatchPhase; import com.yahoo.search.query.restapi.ErrorResponse; import com.yahoo.search.yql.MinimalQueryInserter; import com.yahoo.vespa.config.search.RankProfilesConfig; +import com.yahoo.search.config.IndexInfoConfig; import com.yahoo.yolean.Exceptions; +import org.json.JSONException; +import org.json.JSONObject; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; import java.util.logging.Level; @@ -38,8 +42,6 @@ import java.util.logging.Level; */ public class GUIHandler extends LoggingRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private final IndexModel indexModel; private final RankProfilesConfig rankProfilesConfig; @@ -110,7 +112,7 @@ public class GUIHandler extends LoggingRequestHandler { InputStream is; if (this.path.equals("config.json")){ String json = "{}"; - try { json = getGUIConfig(); } catch (IOException e) { /*Something happened while parsing JSON */ } + try { json = getGUIConfig(); } catch (JSONException e) { /*Something happened while parsing JSON */ } is = new ByteArrayInputStream(json.getBytes()); } else{ is = GUIHandler.class.getClassLoader().getResourceAsStream("gui/"+this.path); @@ -158,50 +160,50 @@ public class GUIHandler extends LoggingRequestHandler { return "text/html"; } - private String getGUIConfig() throws IOException { - ObjectNode json = jsonMapper.createObjectNode(); - json.set("ranking_properties", jsonMapper.createArrayNode().add("propertyname")); - json.set("ranking_features", jsonMapper.createArrayNode().add("featurename")); + private String getGUIConfig() throws JSONException { + JSONObject json = new JSONObject(); + json.put("ranking_properties", Arrays.asList("propertyname")); + json.put("ranking_features", Arrays.asList("featurename")); - ArrayNode sources = jsonMapper.createArrayNode(); + List<String> sources = new ArrayList<>(); try { - indexModel.getMasterClusters().keySet().forEach(sources::add); + sources = new ArrayList<>(indexModel.getMasterClusters().keySet()); } catch (NullPointerException ex){ /* clusters are not set */ } - json.set("model_sources", sources); + json.put("model_sources", sources); - ArrayNode rankProfiles = jsonMapper.createArrayNode(); + List<String> rankProfiles = new ArrayList<>(); try { rankProfilesConfig.rankprofile().forEach(rankProfile -> rankProfiles.add(rankProfile.name())); } catch (NullPointerException ex){ /* rankprofiles are not set*/ } - json.set("ranking_profile", rankProfiles); + json.put("ranking_profile", rankProfiles); // Creating map from parent to children for GUI: parameter --> child-parameters - ObjectNode childMap = jsonMapper.createObjectNode(); - childMap.set(Model.MODEL, jsonMapper.createArrayNode().add(Model.DEFAULT_INDEX).add(Model.ENCODING).add(Model.LANGUAGE).add(Model.QUERY_STRING).add(Model.RESTRICT).add(Model.SEARCH_PATH).add(Model.SOURCES).add(Model.TYPE)); - childMap.set(Ranking.RANKING, jsonMapper.createArrayNode().add(Ranking.LOCATION).add(Ranking.FEATURES).add(Ranking.LIST_FEATURES).add(Ranking.PROFILE).add(Ranking.PROPERTIES).add(Ranking.SORTING).add(Ranking.FRESHNESS).add(Ranking.QUERYCACHE).add(Ranking.MATCH_PHASE)); - childMap.set(Ranking.RANKING +"."+ Ranking.MATCH_PHASE, jsonMapper.createArrayNode().add(MatchPhase.MAX_HITS).add(MatchPhase.ATTRIBUTE).add(MatchPhase.ASCENDING).add(Ranking.DIVERSITY)); - childMap.set(Ranking.RANKING +"."+ Ranking.MATCH_PHASE +"."+Ranking.DIVERSITY, jsonMapper.createArrayNode().add(Diversity.ATTRIBUTE).add(Diversity.MINGROUPS)); - childMap.set(Presentation.PRESENTATION, jsonMapper.createArrayNode().add(Presentation.BOLDING).add(Presentation.FORMAT).add(Presentation.SUMMARY).add("template").add(Presentation.TIMING )); - childMap.set("trace", jsonMapper.createArrayNode().add("timestamps")); - childMap.set("tracelevel", jsonMapper.createArrayNode().add("rules")); - childMap.set("metrics", jsonMapper.createArrayNode().add("ignore")); - childMap.set("collapse", jsonMapper.createArrayNode().add("summary")); - childMap.set("pos", jsonMapper.createArrayNode().add("ll").add("radius").add("bb").add("attribute")); - childMap.set("streaming", jsonMapper.createArrayNode().add("userid").add("groupname").add("selection").add("priority").add("maxbucketspervisitor")); - childMap.set("rules", jsonMapper.createArrayNode().add("off").add("rulebase")); - json.set("childMap", childMap); - - ArrayNode levelZeroParameters = jsonMapper.createArrayNode().add(MinimalQueryInserter.YQL.toString()).add(Query.HITS.toString()).add(Query.OFFSET.toString()) - .add("queryProfile").add(Query.NO_CACHE.toString()).add(Query.GROUPING_SESSION_CACHE.toString()) - .add(Query.SEARCH_CHAIN.toString()).add(Query.TIMEOUT.toString()).add("trace").add("tracelevel") - .add(Query.TRACE_LEVEL.toString()).add(Query.EXPLAIN_LEVEL.toString()).add("explainlevel").add(Model.MODEL).add(Ranking.RANKING).add("collapse").add("collapsesize").add("collapsefield") - .add(Presentation.PRESENTATION).add("pos").add("streaming").add("rules").add(RecallSearcher.recallName.toString()).add("user") - .add("metrics").add(""); - json.set("levelZeroParameters", levelZeroParameters); - - return jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json); + HashMap<String, List<String>> childMap = new HashMap<>(); + childMap.put(Model.MODEL, Arrays.asList(Model.DEFAULT_INDEX, Model.ENCODING, Model.LANGUAGE, Model.QUERY_STRING, Model.RESTRICT, Model.SEARCH_PATH, Model.SOURCES, Model.TYPE)); + childMap.put(Ranking.RANKING, Arrays.asList(Ranking.LOCATION, Ranking.FEATURES, Ranking.LIST_FEATURES, Ranking.PROFILE, Ranking.PROPERTIES, Ranking.SORTING, Ranking.FRESHNESS, Ranking.QUERYCACHE, Ranking.MATCH_PHASE)); + childMap.put(Ranking.RANKING +"."+ Ranking.MATCH_PHASE, Arrays.asList(MatchPhase.MAX_HITS, MatchPhase.ATTRIBUTE, MatchPhase.ASCENDING, Ranking.DIVERSITY)); + childMap.put(Ranking.RANKING +"."+ Ranking.MATCH_PHASE +"."+Ranking.DIVERSITY, Arrays.asList(Diversity.ATTRIBUTE, Diversity.MINGROUPS)); + childMap.put(Presentation.PRESENTATION, Arrays.asList(Presentation.BOLDING, Presentation.FORMAT, Presentation.SUMMARY, "template", Presentation.TIMING )); + childMap.put("trace", Arrays.asList("timestamps")); + childMap.put("tracelevel", Arrays.asList("rules")); + childMap.put("metrics", Arrays.asList("ignore")); + childMap.put("collapse", Arrays.asList("summary")); + childMap.put("pos", Arrays.asList("ll", "radius", "bb", "attribute")); + childMap.put("streaming", Arrays.asList("userid", "groupname", "selection", "priority", "maxbucketspervisitor")); + childMap.put("rules", Arrays.asList("off", "rulebase")); + json.put("childMap", childMap); + + List<String> levelZeroParameters = Arrays.asList(MinimalQueryInserter.YQL.toString(), Query.HITS.toString(), Query.OFFSET.toString(), + "queryProfile", Query.NO_CACHE.toString(), Query.GROUPING_SESSION_CACHE.toString(), + Query.SEARCH_CHAIN.toString(), Query.TIMEOUT.toString(), "trace", "tracelevel", + Query.TRACE_LEVEL.toString(), Query.EXPLAIN_LEVEL.toString(), "explainlevel", Model.MODEL, Ranking.RANKING, "collapse", "collapsesize","collapsefield", + Presentation.PRESENTATION, "pos", "streaming", "rules", RecallSearcher.recallName.toString(), "user", + "metrics", ""); + json.put("levelZeroParameters", levelZeroParameters); + + return json.toString(); } } }
\ No newline at end of file diff --git a/container-search/pom.xml b/container-search/pom.xml index 014b7dda14f..074f5827122 100644 --- a/container-search/pom.xml +++ b/container-search/pom.xml @@ -150,11 +150,6 @@ <version>${project.version}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>org.assertj</groupId> - <artifactId>assertj-core</artifactId> - <scope>test</scope> - </dependency> </dependencies> <build> <plugins> diff --git a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java index 55438aa35ba..209bfd08e6b 100644 --- a/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java +++ b/container-search/src/main/java/com/yahoo/prelude/hitfield/JSONString.java @@ -21,7 +21,6 @@ import java.util.Iterator; * * @author Steinar Knutsen */ -// TODO Vespa 8: remove methods leaking org.json types (replace with Slime equivalent?) public class JSONString implements Inspectable { private Inspector value; @@ -437,8 +436,6 @@ public class JSONString implements Inspectable { return content; } - /** @deprecated Use {@link #getContent()} instead and parse content yourself */ - @Deprecated(forRemoval = true, since = "7") public Object getParsedJSON() { initContent(); if (parsedJSON == null) { @@ -447,7 +444,6 @@ public class JSONString implements Inspectable { return parsedJSON; } - @Deprecated(forRemoval = true, since = "7") public void setParsedJSON(Object parsedJSON) { this.parsedJSON = parsedJSON; } diff --git a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java index c4f850307ae..31f8194b3b7 100644 --- a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java +++ b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java @@ -45,6 +45,8 @@ import com.yahoo.search.result.Hit; import com.yahoo.search.result.HitGroup; import com.yahoo.search.result.NanNumber; import com.yahoo.tensor.Tensor; +import org.json.JSONArray; +import org.json.JSONObject; import java.io.IOException; import java.io.OutputStream; @@ -669,6 +671,14 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> { } else if (field instanceof FieldValue) { // the null below is the field which has already been written ((FieldValue) field).serialize(null, new JsonWriter(generator)); + } else if (field instanceof JSONArray || field instanceof JSONObject) { + // org.json returns null if the object would not result in syntactically correct JSON + String s = field.toString(); + if (s == null) { + generator.writeNull(); + } else { + generator.writeRawValue(s); + } } else { generator.writeString(field.toString()); } diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java index 49df321e581..d1399cabc75 100644 --- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java @@ -4,21 +4,16 @@ package com.yahoo.prelude.fastsearch; import com.google.common.collect.ImmutableSet; import com.yahoo.config.subscription.ConfigGetter; import com.yahoo.data.access.slime.SlimeAdapter; -import com.yahoo.prelude.hitfield.JSONString; import com.yahoo.prelude.hitfield.RawData; import com.yahoo.prelude.hitfield.XMLString; +import com.yahoo.prelude.hitfield.JSONString; import com.yahoo.search.result.FeatureData; import com.yahoo.search.result.Hit; +import com.yahoo.search.result.NanNumber; import com.yahoo.search.result.StructuredData; -import com.yahoo.slime.BinaryFormat; -import com.yahoo.slime.Cursor; -import com.yahoo.slime.Slime; -import com.yahoo.tensor.Tensor; -import com.yahoo.tensor.serialization.TypedBinaryFormat; -import org.junit.Test; - import java.nio.ByteBuffer; import java.nio.ByteOrder; + import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Iterator; @@ -26,6 +21,14 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import com.yahoo.slime.BinaryFormat; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.Slime; +import com.yahoo.tensor.Tensor; +import com.yahoo.tensor.serialization.TypedBinaryFormat; +import org.junit.Test; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -99,7 +102,7 @@ public class SlimeSummaryTestCase { if (hit.getField("jsonstring_field") instanceof JSONString) { JSONString jstr = (JSONString) hit.getField("jsonstring_field"); assertEquals("{\"foo\":1,\"bar\":2}", jstr.getContent()); - assertNotNull(getParsedJSON(jstr)); + assertNotNull(jstr.getParsedJSON()); com.yahoo.data.access.Inspector value = jstr.inspect(); assertEquals(1L, value.field("foo").asLong()); @@ -123,8 +126,6 @@ public class SlimeSummaryTestCase { assertEquals(tensor2, featureData.getTensor("tensor2_feature")); } - @SuppressWarnings("removal") private static Object getParsedJSON(JSONString jstr) { return jstr.getParsedJSON(); } - @Test public void testFieldAccessAPI() { DocsumDefinitionSet partialDocsum1 = createDocsumDefinitionSet(partial_summary1_cf); diff --git a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java index 80e629ca4cb..3cca053d0e5 100644 --- a/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/handler/test/JSONSearchHandlerTestCase.java @@ -1,13 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.handler.test; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.container.Container; import com.yahoo.container.core.config.testutil.HandlersConfigurerTestWrapper; import com.yahoo.container.jdisc.HttpRequest; + import com.yahoo.container.jdisc.RequestHandlerTestDriver; import com.yahoo.container.protect.Error; import com.yahoo.io.IOUtils; @@ -16,8 +13,8 @@ import com.yahoo.search.handler.SearchHandler; import com.yahoo.search.searchchain.config.test.SearchChainConfigurerTestCase; import com.yahoo.slime.Inspector; import com.yahoo.slime.SlimeUtils; -import com.yahoo.test.json.JsonTestHelper; -import org.assertj.core.api.Assertions; +import org.json.JSONArray; +import org.json.JSONObject; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -26,19 +23,13 @@ import org.junit.rules.TemporaryFolder; import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; import java.util.Map; +import java.util.HashMap; import static com.yahoo.jdisc.http.HttpRequest.Method.GET; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; /** * Tests submitting the query as JSON. @@ -47,8 +38,6 @@ import static org.junit.Assert.assertTrue; */ public class JSONSearchHandlerTestCase { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String testDir = "src/test/java/com/yahoo/search/handler/test/config"; private static final String myHostnameHeader = "my-hostname-header"; private static final String selfHostname = HostName.getLocalhost(); @@ -108,8 +97,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testFailing() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testFailing() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "test"); json.put("searchChain", "classLoadingError"); assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NoClassDefFoundError")); @@ -117,16 +106,16 @@ public class JSONSearchHandlerTestCase { @Test - public synchronized void testPluginError() { - ObjectNode json = jsonMapper.createObjectNode(); + public synchronized void testPluginError() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "test"); json.put("searchChain", "exceptionInPlugin"); assertTrue(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE).readAll().contains("NullPointerException")); } @Test - public synchronized void testWorkingReconfiguration() throws IOException { - ObjectNode json = jsonMapper.createObjectNode(); + public synchronized void testWorkingReconfiguration() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); assertJsonResult(json, driver); @@ -146,7 +135,7 @@ public class JSONSearchHandlerTestCase { } @Test - public void testInvalidYqlQuery() throws IOException { + public void testInvalidYqlQuery() throws Exception { IOUtils.copyDirectory(new File(testDir, "config_yql"), new File(tempDir), 1); generateComponentsConfigForActive(); configurer.reloadConfig(); @@ -154,7 +143,7 @@ public class JSONSearchHandlerTestCase { SearchHandler newSearchHandler = fetchSearchHandler(configurer); assertTrue("Do I have a new instance of the search handler?", searchHandler != newSearchHandler); try (RequestHandlerTestDriver newDriver = new RequestHandlerTestDriver(newSearchHandler)) { - ObjectNode json = jsonMapper.createObjectNode(); + JSONObject json = new JSONObject(); json.put("yql", "select * from foo where bar > 1453501295"); RequestHandlerTestDriver.MockResponseHandler responseHandler = newDriver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); responseHandler.readAll(); @@ -164,14 +153,14 @@ public class JSONSearchHandlerTestCase { // Query handling takes a different code path when a query profile is active, so we test both paths. @Test - public void testInvalidQueryParamWithQueryProfile() throws IOException { + public void testInvalidQueryParamWithQueryProfile() throws Exception { try (RequestHandlerTestDriver newDriver = driverWithConfig("config_invalid_param")) { testInvalidQueryParam(newDriver); } } - private void testInvalidQueryParam(final RequestHandlerTestDriver testDriver) { - ObjectNode json = jsonMapper.createObjectNode(); + private void testInvalidQueryParam(final RequestHandlerTestDriver testDriver) throws Exception { + JSONObject json = new JSONObject(); json.put("query", "status_code:0"); json.put("hits", 20); json.put("offset", -20); @@ -184,16 +173,16 @@ public class JSONSearchHandlerTestCase { } @Test - public void testNormalResultJsonAliasRendering() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultJsonAliasRendering() throws Exception { + JSONObject json = new JSONObject(); json.put("format", "json"); json.put("query", "abc"); assertJsonResult(json, driver); } @Test - public void testNullQuery() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNullQuery() throws Exception { + JSONObject json = new JSONObject(); json.put("format", "xml"); assertEquals("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" + @@ -206,8 +195,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testWebServiceStatus() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testWebServiceStatus() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "web_service_status_code"); RequestHandlerTestDriver.MockResponseHandler responseHandler = driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE); @@ -217,39 +206,39 @@ public class JSONSearchHandlerTestCase { } @Test - public void testNormalResultImplicitDefaultRendering() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultImplicitDefaultRendering() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); assertJsonResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRendering() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultExplicitDefaultRendering() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); json.put("format", "default"); assertJsonResult(json, driver); } @Test - public void testNormalResultXmlAliasRendering() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultXmlAliasRendering() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); json.put("format", "xml"); assertXmlResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRenderingFullRendererName1() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultExplicitDefaultRenderingFullRendererName1() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); json.put("format", "XmlRenderer"); assertXmlResult(json, driver); } @Test - public void testNormalResultExplicitDefaultRenderingFullRendererName2() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testNormalResultExplicitDefaultRenderingFullRendererName2() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); json.put("format", "JsonRenderer"); assertJsonResult(json, driver); @@ -264,7 +253,7 @@ public class JSONSearchHandlerTestCase { " </hit>\n" + "</result>\n"; - private void assertXmlResult(JsonNode json, RequestHandlerTestDriver driver) { + private void assertXmlResult(JSONObject json, RequestHandlerTestDriver driver) { assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), xmlResult); } @@ -274,7 +263,7 @@ public class JSONSearchHandlerTestCase { + "{\"id\":\"testHit\",\"relevance\":1.0,\"fields\":{\"uri\":\"testHit\"}}" + "]}}"; - private void assertJsonResult(JsonNode json, RequestHandlerTestDriver driver) { + private void assertJsonResult(JSONObject json, RequestHandlerTestDriver driver) { assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), JSON_CONTENT_TYPE), jsonResult); } @@ -299,7 +288,7 @@ public class JSONSearchHandlerTestCase { } - private RequestHandlerTestDriver driverWithConfig(String configDirectory) throws IOException { + private RequestHandlerTestDriver driverWithConfig(String configDirectory) throws Exception { IOUtils.copyDirectory(new File(testDir, configDirectory), new File(tempDir), 1); generateComponentsConfigForActive(); configurer.reloadConfig(); @@ -310,44 +299,44 @@ public class JSONSearchHandlerTestCase { } @Test - public void testSelectParameters() throws IOException { - ObjectNode json = jsonMapper.createObjectNode(); + public void testSelectParameters() throws Exception { + JSONObject json = new JSONObject(); - ObjectNode select = jsonMapper.createObjectNode(); + JSONObject select = new JSONObject(); - ObjectNode where = jsonMapper.createObjectNode(); + JSONObject where = new JSONObject(); where.put("where", "where"); - ObjectNode grouping = jsonMapper.createObjectNode(); + JSONObject grouping = new JSONObject(); grouping.put("grouping", "grouping"); - select.set("where", where); - select.set("grouping", grouping); + select.put("where", where); + select.put("grouping", grouping); - json.set("select", select); + json.put("select", select); - Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes(StandardCharsets.UTF_8)).get(); + Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes("utf-8")).get(); Map<String, String> map = new HashMap<>(); searchHandler.createRequestMapping(inspector, map, ""); - JsonNode processedWhere = jsonMapper.readTree(map.get("select.where")); - JsonTestHelper.assertJsonEquals(where.toString(), processedWhere.toString()); + JSONObject processedWhere = new JSONObject(map.get("select.where")); + assertEquals(where.toString(), processedWhere.toString()); - JsonNode processedGrouping = jsonMapper.readTree(map.get("select.grouping")); - JsonTestHelper.assertJsonEquals(grouping.toString(), processedGrouping.toString()); + JSONObject processedGrouping = new JSONObject(map.get("select.grouping")); + assertEquals(grouping.toString(), processedGrouping.toString()); } @Test - public void testJsonQueryWithSelectWhere() { - ObjectNode root = jsonMapper.createObjectNode(); - ObjectNode select = jsonMapper.createObjectNode(); - ObjectNode where = jsonMapper.createObjectNode(); - ArrayNode term = jsonMapper.createArrayNode(); - term.add("default"); - term.add("bad"); - where.set("contains", term); - select.set("where", where); - root.set("select", select); + public void testJsonQueryWithSelectWhere() throws Exception { + JSONObject root = new JSONObject(); + JSONObject select = new JSONObject(); + JSONObject where = new JSONObject(); + JSONArray term = new JSONArray(); + term.put("default"); + term.put("bad"); + where.put("contains", term); + select.put("where", where); + root.put("select", select); // Run query String result = driver.sendRequest(uri + "searchChain=echoingQuery", com.yahoo.jdisc.http.HttpRequest.Method.POST, root.toString(), JSON_CONTENT_TYPE).readAll(); @@ -404,8 +393,8 @@ public class JSONSearchHandlerTestCase { } @Test - public void testJsonQueryWithYQL() { - ObjectNode root = jsonMapper.createObjectNode(); + public void testJsonQueryWithYQL() throws Exception { + JSONObject root = new JSONObject(); root.put("yql", "select * from sources * where default contains 'bad';"); // Run query @@ -415,10 +404,10 @@ public class JSONSearchHandlerTestCase { } @Test - public void testRequestMapping() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testRequestMapping() throws Exception { + JSONObject json = new JSONObject(); json.put("yql", "select * from sources * where sddocname contains \"blog_post\" limit 0 | all(group(date) max(3) order(-count())each(output(count())));"); - json.put("hits", 10); + json.put("hits", 10.0); json.put("offset", 5); json.put("queryProfile", "foo"); json.put("nocache", false); @@ -428,7 +417,7 @@ public class JSONSearchHandlerTestCase { json.put("select", "_all"); - ObjectNode model = jsonMapper.createObjectNode(); + JSONObject model = new JSONObject(); model.put("defaultIndex", 1); model.put("encoding", "json"); model.put("filter", "default"); @@ -438,9 +427,9 @@ public class JSONSearchHandlerTestCase { model.put("searchPath", "node1"); model.put("sources", "source1,source2"); model.put("type", "yql"); - json.set("model", model); + json.put("model", model); - ObjectNode ranking = jsonMapper.createObjectNode(); + JSONObject ranking = new JSONObject(); ranking.put("location", "123789.89123N;128123W"); ranking.put("features", "none"); ranking.put("listFeatures", false); @@ -450,61 +439,61 @@ public class JSONSearchHandlerTestCase { ranking.put("freshness", "0.05"); ranking.put("queryCache", false); - ObjectNode matchPhase = jsonMapper.createObjectNode(); + JSONObject matchPhase = new JSONObject(); matchPhase.put("maxHits", "100"); matchPhase.put("attribute", "title"); matchPhase.put("ascending", true); - ObjectNode diversity = jsonMapper.createObjectNode(); + JSONObject diversity = new JSONObject(); diversity.put("attribute", "title"); diversity.put("minGroups", 1); - matchPhase.set("diversity", diversity); - ranking.set("matchPhase", matchPhase); - json.set("ranking", ranking); + matchPhase.put("diversity", diversity); + ranking.put("matchPhase", matchPhase); + json.put("ranking", ranking); - ObjectNode presentation = jsonMapper.createObjectNode(); + JSONObject presentation = new JSONObject(); presentation.put("bolding", true); presentation.put("format", "json"); presentation.put("summary", "none"); presentation.put("template", "json"); presentation.put("timing", false); - json.set("presentation", presentation); + json.put("presentation", presentation); - ObjectNode collapse = jsonMapper.createObjectNode(); + JSONObject collapse = new JSONObject(); collapse.put("field", "none"); collapse.put("size", 2); collapse.put("summary", "default"); - json.set("collapse", collapse); + json.put("collapse", collapse); - ObjectNode trace = jsonMapper.createObjectNode(); + JSONObject trace = new JSONObject(); trace.put("level", 1); trace.put("timestamps", false); trace.put("rules", "none"); - json.set("trace", trace); + json.put("trace", trace); - ObjectNode pos = jsonMapper.createObjectNode(); + JSONObject pos = new JSONObject(); pos.put("ll", "1263123N;1231.9W"); pos.put("radius", "71234m"); pos.put("bb", "1237123W;123218N"); pos.put("attribute", "default"); - json.set("pos", pos); + json.put("pos", pos); - ObjectNode streaming = jsonMapper.createObjectNode(); + JSONObject streaming = new JSONObject(); streaming.put("userid", 123); streaming.put("groupname", "abc"); streaming.put("selection", "none"); streaming.put("priority", 10); streaming.put("maxbucketspervisitor", 5); - json.set("streaming", streaming); + json.put("streaming", streaming); - ObjectNode rules = jsonMapper.createObjectNode(); + JSONObject rules = new JSONObject(); rules.put("off", false); rules.put("rulebase", "default"); - json.set("rules", rules); + json.put("rules", rules); - ObjectNode metrics = jsonMapper.createObjectNode(); + JSONObject metrics = new JSONObject(); metrics.put("ignore", "_all"); - json.set("metrics", metrics); + json.put("metrics", metrics); json.put("recall", "none"); json.put("user", 123); @@ -512,7 +501,7 @@ public class JSONSearchHandlerTestCase { json.put("hitcountestimate", true); // Create mapping - Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes(StandardCharsets.UTF_8)).get(); + Inspector inspector = SlimeUtils.jsonToSlime(json.toString().getBytes("utf-8")).get(); Map<String, String> map = new HashMap<>(); searchHandler.createRequestMapping(inspector, map, ""); @@ -529,12 +518,12 @@ public class JSONSearchHandlerTestCase { // Get mapping Map<String, String> propertyMap = request.propertyMap(); - Assertions.assertThat(propertyMap).isEqualTo(map); + assertEquals("Should have same mapping for properties", map, propertyMap); } @Test - public void testContentTypeParsing() { - ObjectNode json = jsonMapper.createObjectNode(); + public void testContentTypeParsing() throws Exception { + JSONObject json = new JSONObject(); json.put("query", "abc"); assertOkResult(driver.sendRequest(uri, com.yahoo.jdisc.http.HttpRequest.Method.POST, json.toString(), "Application/JSON; charset=utf-8"), jsonResult); } diff --git a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java index 48003f6586f..c4d49c11f5e 100644 --- a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java +++ b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.search.rendering; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; @@ -55,6 +56,9 @@ import com.yahoo.tensor.TensorType; import com.yahoo.tensor.serialization.TypedBinaryFormat; import com.yahoo.text.Utf8; import com.yahoo.yolean.trace.TraceNode; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Before; import org.junit.Test; @@ -63,6 +67,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; @@ -78,8 +83,6 @@ import static org.junit.Assert.assertTrue; */ public class JsonRendererTestCase { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private JsonRenderer originalRenderer; private JsonRenderer renderer; @@ -956,7 +959,7 @@ public class JsonRendererTestCase { } @Test - public void testJsonObjects() throws InterruptedException, ExecutionException, IOException { + public void testJsonObjects() throws InterruptedException, ExecutionException, IOException, JSONException { String expected = "{" + " \"root\": {" + " \"children\": [" @@ -970,6 +973,14 @@ public class JsonRendererTestCase { + " }," + " \"json producer\": {" + " \"long in structured\": 7809531904" + + " }," + + " \"org.json array\": [" + + " true," + + " true," + + " false" + + " ]," + + " \"org.json object\": {" + + " \"forty-two\": 42" + " }" + " }," + " \"id\": \"json objects\"," @@ -985,17 +996,26 @@ public class JsonRendererTestCase { + "}"; Result r = newEmptyResult(); Hit h = new Hit("json objects"); - ObjectNode j = jsonMapper.createObjectNode(); + JSONObject o = new JSONObject(); + JSONArray a = new JSONArray(); + ObjectMapper mapper = new ObjectMapper(); + JsonNode j = mapper.createObjectNode(); JSONString s = new JSONString("{\"a\": \"b\"}"); Slime slime = new Slime(); Cursor c = slime.setObject(); c.setLong("long in structured", 7809531904L); SlimeAdapter slimeInit = new SlimeAdapter(slime.get()); StructuredData struct = new StructuredData(slimeInit); - j.put("Nineteen-eighty-four", 1984); + ((ObjectNode) j).put("Nineteen-eighty-four", 1984); + o.put("forty-two", 42); + a.put(true); + a.put(true); + a.put(false); h.setField("inspectable", s); h.setField("jackson", j); h.setField("json producer", struct); + h.setField("org.json array", a); + h.setField("org.json object", o); r.hits().add(h); String summary = render(r); assertEqualJson(expected, summary); @@ -1216,13 +1236,11 @@ public class JsonRendererTestCase { public void testThatTheJsonValidatorCanCatchErrors() { String json = "{" + " \"root\": {" - + " \"invalidvalue\": 1adsf," + + " \"duplicate\": 1," + + " \"duplicate\": 2" + " }" + "}"; - assertEquals( - "Unexpected character ('a' (code 97)): was expecting comma to separate Object entries\n" + - " at [Source: { \"root\": { \"invalidvalue\": 1adsf, }}; line: 1, column: 41]", - validateJSON(json)); + assertEquals("Duplicate key \"duplicate\"", validateJSON(json)); } @Test @@ -1298,9 +1316,9 @@ public class JsonRendererTestCase { private String validateJSON(String presumablyValidJson) { try { - jsonMapper.readTree(presumablyValidJson); + new JSONObject(presumablyValidJson); return ""; - } catch (IOException e) { + } catch (JSONException e) { return e.getMessage(); } } diff --git a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java index 9bcd3addd92..3239a97a094 100644 --- a/container-search/src/test/java/com/yahoo/select/SelectTestCase.java +++ b/container-search/src/test/java/com/yahoo/select/SelectTestCase.java @@ -1,9 +1,6 @@ // Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.select; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.yahoo.prelude.query.AndItem; import com.yahoo.prelude.query.ExactStringItem; import com.yahoo.prelude.query.Item; @@ -20,15 +17,19 @@ import com.yahoo.prelude.query.WordItem; import com.yahoo.processing.IllegalInputException; import com.yahoo.search.Query; import com.yahoo.search.grouping.GroupingRequest; +import com.yahoo.search.grouping.request.AllOperation; import com.yahoo.search.query.QueryTree; import com.yahoo.search.query.Select; import com.yahoo.search.query.SelectParser; import com.yahoo.search.query.parser.Parsable; import com.yahoo.search.query.parser.ParserEnvironment; import com.yahoo.search.yql.VespaGroupingStep; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static org.junit.Assert.assertEquals; @@ -47,18 +48,15 @@ import static org.junit.Assert.fail; */ public class SelectTestCase { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private final SelectParser parser = new SelectParser(new ParserEnvironment()); //------------------------------------------------------------------- "where" tests @Test - public void test_contains() { - ObjectNode json = jsonMapper.createObjectNode(); - ArrayNode arrayNode = jsonMapper.createArrayNode(); - arrayNode.add("default").add("foo"); - json.set("contains", arrayNode); + public void test_contains() throws Exception { + JSONObject json = new JSONObject(); + List<String> contains = Arrays.asList("default", "foo"); + json.put("contains", contains); assertParse(json.toString(), "default:foo"); } @@ -79,21 +77,21 @@ public class SelectTestCase { @Test public void testOr() throws Exception { - ObjectNode json_two_or = jsonMapper.createObjectNode(); - ObjectNode json_three_or = jsonMapper.createObjectNode(); - ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); - ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); - ArrayNode contains3 = jsonMapper.createArrayNode().add("title").add("angel"); - - ObjectNode contains_json1 = jsonMapper.createObjectNode(); - ObjectNode contains_json2 = jsonMapper.createObjectNode(); - ObjectNode contains_json3 = jsonMapper.createObjectNode(); - contains_json1.set("contains", contains1); - contains_json2.set("contains", contains2); - contains_json3.set("contains", contains3); - - json_two_or.set("or", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); - json_three_or.set("or", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2).add(contains_json3)); + JSONObject json_two_or = new JSONObject(); + JSONObject json_three_or = new JSONObject(); + List<String> contains1 = Arrays.asList("title", "madonna"); + List<String> contains2 = Arrays.asList("title", "saint"); + List<String> contains3 = Arrays.asList("title", "angel"); + + JSONObject contains_json1 = new JSONObject(); + JSONObject contains_json2 = new JSONObject(); + JSONObject contains_json3 = new JSONObject(); + contains_json1.put("contains", contains1); + contains_json2.put("contains", contains2); + contains_json3.put("contains", contains3); + + json_two_or.put("or", Arrays.asList(contains_json1, contains_json2)); + json_three_or.put("or", Arrays.asList(contains_json1, contains_json2, contains_json3)); assertParse(json_two_or.toString(), "OR title:madonna title:saint"); assertParse(json_three_or.toString(), "OR title:madonna title:saint title:angel"); @@ -101,178 +99,178 @@ public class SelectTestCase { @Test public void testAnd() throws Exception{ - ObjectNode json_two_and = jsonMapper.createObjectNode(); - ObjectNode json_three_and = jsonMapper.createObjectNode(); - ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); - ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); - ArrayNode contains3 = jsonMapper.createArrayNode().add("title").add("angel"); - - ObjectNode contains_json1 = jsonMapper.createObjectNode(); - ObjectNode contains_json2 = jsonMapper.createObjectNode(); - ObjectNode contains_json3 = jsonMapper.createObjectNode(); - contains_json1.set("contains", contains1); - contains_json2.set("contains", contains2); - contains_json3.set("contains", contains3); - - json_two_and.set("and", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); - json_three_and.set("and", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2).add(contains_json3)); + JSONObject json_two_and = new JSONObject(); + JSONObject json_three_and = new JSONObject(); + List<String> contains1 = Arrays.asList("title", "madonna"); + List<String> contains2 = Arrays.asList("title", "saint"); + List<String> contains3 = Arrays.asList("title", "angel"); + + JSONObject contains_json1 = new JSONObject(); + JSONObject contains_json2 = new JSONObject(); + JSONObject contains_json3 = new JSONObject(); + contains_json1.put("contains", contains1); + contains_json2.put("contains", contains2); + contains_json3.put("contains", contains3); + + json_two_and.put("and", Arrays.asList(contains_json1, contains_json2)); + json_three_and.put("and", Arrays.asList(contains_json1, contains_json2, contains_json3)); assertParse(json_two_and.toString(), "AND title:madonna title:saint"); assertParse(json_three_and.toString(), "AND title:madonna title:saint title:angel"); } @Test - public void testAndNot() { - ObjectNode json_and_not = jsonMapper.createObjectNode(); - ArrayNode contains1 = jsonMapper.createArrayNode().add("title").add("madonna"); - ArrayNode contains2 = jsonMapper.createArrayNode().add("title").add("saint"); + public void testAndNot() throws JSONException { + JSONObject json_and_not = new JSONObject(); + List<String> contains1 = Arrays.asList("title", "madonna"); + List<String> contains2 = Arrays.asList("title", "saint"); - ObjectNode contains_json1 = jsonMapper.createObjectNode(); - ObjectNode contains_json2 = jsonMapper.createObjectNode(); - contains_json1.set("contains", contains1); - contains_json2.set("contains", contains2); + JSONObject contains_json1 = new JSONObject(); + JSONObject contains_json2 = new JSONObject(); + contains_json1.put("contains", contains1); + contains_json2.put("contains", contains2); - json_and_not.set("and_not", jsonMapper.createArrayNode().add(contains_json1).add(contains_json2)); + json_and_not.put("and_not", Arrays.asList(contains_json1, contains_json2)); assertParse(json_and_not.toString(), "+title:madonna -title:saint"); } @Test - public void testLessThan() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testLessThan() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("<", 500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:<500"); } @Test - public void testGreaterThan() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testGreaterThan() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put(">", 500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:>500"); } @Test - public void testLessThanOrEqual() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testLessThanOrEqual() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("<=", 500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:[;500]"); } @Test - public void testGreaterThanOrEqual() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testGreaterThanOrEqual() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put(">=", 500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:[500;]"); } @Test - public void testEquality() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testEquality() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("=", 500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:500"); } @Test - public void testNegativeLessThan() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testNegativeLessThan() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("<", -500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:<-500"); } @Test - public void testNegativeGreaterThan() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testNegativeGreaterThan() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put(">", -500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:>-500"); } @Test - public void testNegativeLessThanOrEqual() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testNegativeLessThanOrEqual() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("<=", -500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:[;-500]"); } @Test - public void testNegativeGreaterThanOrEqual() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testNegativeGreaterThanOrEqual() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put(">=", -500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:[-500;]"); } @Test - public void testNegativeEquality() { - ObjectNode range_json = jsonMapper.createObjectNode(); - ObjectNode operators = jsonMapper.createObjectNode(); + public void testNegativeEquality() throws JSONException { + JSONObject range_json = new JSONObject(); + JSONObject operators = new JSONObject(); operators.put("=", -500); - ArrayNode range = jsonMapper.createArrayNode().add("price").add(operators); + List<Object> range = Arrays.asList("price", operators); - range_json.set("range", range); + range_json.put("range", range); assertParse(range_json.toString(), "price:-500"); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java index ed88902e094..c6d907ec7fc 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/model/ProtonMetrics.java @@ -1,19 +1,14 @@ package com.yahoo.vespa.hosted.controller.api.application.v4.model; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - import java.util.HashMap; import java.util.Map; -import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; +import org.json.JSONException; +import org.json.JSONObject; public class ProtonMetrics { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final Logger logger = LogManager.getLogManager().getLogger(ProtonMetrics.class.getName()); public static final String DOCUMENTS_ACTIVE_COUNT = "documentsActiveCount"; @@ -50,19 +45,19 @@ public class ProtonMetrics { return this; } - public JsonNode toJson() { + public JSONObject toJson() { try { - ObjectNode protonMetrics = jsonMapper.createObjectNode(); + JSONObject protonMetrics = new JSONObject(); protonMetrics.put("clusterId", clusterId); - ObjectNode jsonMetrics = jsonMapper.createObjectNode(); + JSONObject jsonMetrics = new JSONObject(); for (Map.Entry<String, Double> entry : metrics.entrySet()) { jsonMetrics.put(entry.getKey(), entry.getValue()); } - protonMetrics.set("metrics", jsonMetrics); + protonMetrics.put("metrics", jsonMetrics); return protonMetrics; - } catch (Exception e) { - logger.log(Level.SEVERE, "Unable to convert Proton Metrics to JSON Object: " + e.getMessage(), e); + } catch (JSONException e) { + logger.severe("Unable to convert Proton Metrics to JSON Object"); } - return jsonMapper.createObjectNode(); + return new JSONObject(); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 431a694fcd8..5a1496bf507 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -2,8 +2,6 @@ package com.yahoo.vespa.hosted.controller.restapi.application; import ai.vespa.hosted.api.Signatures; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; import com.google.inject.Inject; @@ -102,6 +100,9 @@ import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import com.yahoo.vespa.serviceview.bindings.ApplicationView; import com.yahoo.yolean.Exceptions; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import javax.ws.rs.ForbiddenException; import javax.ws.rs.InternalServerErrorException; @@ -150,8 +151,6 @@ import static java.util.stream.Collectors.toUnmodifiableList; @SuppressWarnings("unused") // created by injection public class ApplicationApiHandler extends LoggingRequestHandler { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String OPTIONAL_PREFIX = "/api"; private final Controller controller; @@ -790,15 +789,15 @@ public class ApplicationApiHandler extends LoggingRequestHandler { private JsonResponse buildResponseFromProtonMetrics(List<ProtonMetrics> protonMetrics) { try { - var jsonObject = jsonMapper.createObjectNode(); - var jsonArray = jsonMapper.createArrayNode(); + var jsonObject = new JSONObject(); + var jsonArray = new JSONArray(); for (ProtonMetrics metrics : protonMetrics) { - jsonArray.add(metrics.toJson()); + jsonArray.put(metrics.toJson()); } - jsonObject.set("metrics", jsonArray); - return new JsonResponse(200, jsonMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject)); - } catch (JsonProcessingException e) { - log.log(Level.SEVERE, "Unable to build JsonResponse with Proton data: " + e.getMessage(), e); + jsonObject.put("metrics", jsonArray); + return new JsonResponse(200, jsonObject.toString()); + } catch (JSONException e) { + log.severe("Unable to build JsonResponse with Proton data"); return new JsonResponse(500, ""); } } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java index 2bf6eb39089..bda5a708a94 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java @@ -9,7 +9,6 @@ import com.yahoo.config.provision.ApplicationName; import com.yahoo.container.http.filter.FilterChainRepository; import com.yahoo.jdisc.http.filter.SecurityRequestFilter; import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain; -import com.yahoo.test.json.JsonTestHelper; import com.yahoo.vespa.athenz.api.AthenzDomain; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.hosted.controller.Controller; @@ -66,10 +65,6 @@ public class ContainerTester { .addRoleMember(action, identity); } - public void assertJsonResponse(Supplier<Request> request, File responseFile) { - assertResponse(request.get(), responseFile, 200, false, true); - } - public void assertResponse(Supplier<Request> request, File responseFile) { assertResponse(request.get(), responseFile); } @@ -87,10 +82,6 @@ public class ContainerTester { } public void assertResponse(Request request, File responseFile, int expectedStatusCode, boolean removeWhitespace) { - assertResponse(request, responseFile, expectedStatusCode, removeWhitespace, false); - } - - private void assertResponse(Request request, File responseFile, int expectedStatusCode, boolean removeWhitespace, boolean compareJson) { String expectedResponse = readTestFile(responseFile.toString()); expectedResponse = include(expectedResponse); if (removeWhitespace) expectedResponse = expectedResponse.replaceAll("(\"[^\"]*\")|\\s*", "$1"); // Remove whitespace @@ -115,11 +106,7 @@ public class ContainerTester { expectedResponsePattern, responseString); } } else { - if (compareJson) { - JsonTestHelper.assertJsonEquals(expectedResponse, responseString); - } else { - assertEquals(responseFile.toString(), expectedResponse, responseString); - } + assertEquals(responseFile.toString(), expectedResponse, responseString); } assertEquals("Status code", expectedStatusCode, response.getStatus()); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index 63ad8004473..434c83898ee 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -514,7 +514,7 @@ public class ApplicationApiTest extends ControllerContainerTest { updateMetrics(); // GET metrics - tester.assertJsonResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/metrics", GET) + tester.assertResponse(request("/application/v4/tenant/tenant2/application/application1/environment/dev/region/us-east-1/instance/default/metrics", GET) .userIdentity(USER_ID), new File("proton-metrics.json")); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java index c43abf276c5..828e2856cae 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelperTest.java @@ -4,7 +4,6 @@ package com.yahoo.vespa.hosted.controller.restapi.application; import com.yahoo.component.Version; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.container.jdisc.HttpResponse; -import com.yahoo.test.json.JsonTestHelper; import com.yahoo.vespa.hosted.controller.api.application.v4.model.DeployOptions; import com.yahoo.vespa.hosted.controller.api.integration.configserver.ConfigServerException; import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion; @@ -13,6 +12,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.TestReport; import com.yahoo.vespa.hosted.controller.application.ApplicationPackage; import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder; import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -179,10 +180,12 @@ public class JobControllerApiHandlerHelperTest { "jobs-direct-deployment.json"); } - private void compare(HttpResponse response, String expected) throws IOException { + private void compare(HttpResponse response, String expected) throws JSONException, IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); response.render(baos); - JsonTestHelper.assertJsonEquals(expected, baos.toString()); + JSONObject actualJSON = new JSONObject(new String(baos.toByteArray())); + JSONObject expectedJSON = new JSONObject(expected); + assertEquals(expectedJSON.toString(), actualJSON.toString()); } private void assertResponse(HttpResponse response, String fileName) { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json index 3fba9b3c91c..a7e5b3918d8 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/proton-metrics.json @@ -1,26 +1,23 @@ { - "metrics": [ - { - "clusterId": "content/doc/", - "metrics": { - "resourceMemoryUsageAverage": 0.103482, - "documentsReadyCount": 11430.0, - "documentDiskUsage": 44021.0, - "resourceDiskUsageAverage": 0.0168421, - "documentsTotalCount": 11430.0, - "documentsActiveCount": 11430.0 - } - }, - { - "clusterId": "content/music/", - "metrics": { - "resourceMemoryUsageAverage": 0.00912, - "documentsReadyCount": 32000.0, - "documentDiskUsage": 90113.0, - "resourceDiskUsageAverage": 0.23912, - "documentsTotalCount": 32210.0, - "documentsActiveCount": 32210.0 - } + "metrics": [{ + "clusterId": "content/doc/", + "metrics": { + "resourceMemoryUsageAverage": 0.103482, + "documentsReadyCount": 11430, + "documentDiskUsage": 44021, + "resourceDiskUsageAverage": 0.0168421, + "documentsTotalCount": 11430, + "documentsActiveCount": 11430 } - ] -} + }, { + "clusterId": "content/music/", + "metrics": { + "resourceMemoryUsageAverage": 0.00912, + "documentsReadyCount": 32000, + "documentDiskUsage": 90113, + "resourceDiskUsageAverage": 0.23912, + "documentsTotalCount": 32210, + "documentsActiveCount": 32210 + } + }] +}
\ No newline at end of file diff --git a/metrics-proxy/pom.xml b/metrics-proxy/pom.xml index 90d9f093da1..8bf5a30e584 100644 --- a/metrics-proxy/pom.xml +++ b/metrics-proxy/pom.xml @@ -101,6 +101,11 @@ <version>${project.version}</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.json</groupId> + <artifactId>json</artifactId> + <scope>provided</scope> + </dependency> <!-- compile scope --> diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java index 60e8e3deee5..3cd9f526387 100644 --- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java +++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/node/NodeMetricGatherer.java @@ -9,11 +9,13 @@ import ai.vespa.metricsproxy.metric.model.MetricsPacket; import ai.vespa.metricsproxy.metric.model.ServiceId; import ai.vespa.metricsproxy.service.SystemPollerProvider; import ai.vespa.metricsproxy.service.VespaServices; -import com.fasterxml.jackson.databind.JsonNode; import com.google.inject.Inject; import com.yahoo.container.jdisc.state.CoredumpGatherer; import com.yahoo.container.jdisc.state.FileWrapper; import com.yahoo.container.jdisc.state.HostLifeGatherer; +import com.yahoo.yolean.Exceptions; +import org.json.JSONException; +import org.json.JSONObject; import java.util.ArrayList; import java.util.Iterator; @@ -52,10 +54,10 @@ public class NodeMetricGatherer { List<MetricsPacket.Builder> metricPacketBuilders = new ArrayList<>(); metricPacketBuilders.addAll(gatherServiceHealthMetrics(vespaServices)); - JsonNode coredumpPacket = CoredumpGatherer.gatherCoredumpMetrics(fileWrapper); + JSONObject coredumpPacket = CoredumpGatherer.gatherCoredumpMetrics(fileWrapper); addObjectToBuilders(metricPacketBuilders, coredumpPacket); if (SystemPollerProvider.runningOnLinux()) { - JsonNode packet = HostLifeGatherer.getHostLifePacket(fileWrapper); + JSONObject packet = HostLifeGatherer.getHostLifePacket(fileWrapper); addObjectToBuilders(metricPacketBuilders, packet); } @@ -67,20 +69,24 @@ public class NodeMetricGatherer { ).collect(Collectors.toList()); } - protected static void addObjectToBuilders(List<MetricsPacket.Builder> builders, JsonNode object) { - MetricsPacket.Builder builder = new MetricsPacket.Builder(ServiceId.toServiceId(object.get("application").textValue())); - builder.timestamp(object.get("timestamp").longValue()); - if (object.has("status_code")) builder.statusCode(object.get("status_code").intValue()); - if (object.has("status_msg")) builder.statusMessage(object.get("status_msg").textValue()); - if (object.has("metrics")) { - JsonNode metrics = object.get("metrics"); - Iterator<?> keys = metrics.fieldNames(); - while(keys.hasNext()) { - String key = (String) keys.next(); - builder.putMetric(MetricId.toMetricId(key), metrics.get(key).longValue()); + protected static void addObjectToBuilders(List<MetricsPacket.Builder> builders, JSONObject object) { + try { + MetricsPacket.Builder builder = new MetricsPacket.Builder(ServiceId.toServiceId(object.getString("application"))); + builder.timestamp(object.getLong("timestamp")); + if (object.has("status_code")) builder.statusCode(object.getInt("status_code")); + if (object.has("status_msg")) builder.statusMessage(object.getString("status_msg")); + if (object.has("metrics")) { + JSONObject metrics = object.getJSONObject("metrics"); + Iterator<?> keys = metrics.keys(); + while(keys.hasNext()) { + String key = (String) keys.next(); + builder.putMetric(MetricId.toMetricId(key), metrics.getLong(key)); + } } + builders.add(builder); + } catch (JSONException e) { + Exceptions.toMessageString(e); } - builders.add(builder); } } diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java index 6e7bb37d761..1cab1a859a9 100644 --- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java +++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteHealthMetricFetcher.java @@ -2,10 +2,9 @@ package ai.vespa.metricsproxy.service; import ai.vespa.metricsproxy.metric.HealthMetric; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - import java.util.logging.Level; +import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.util.logging.Logger; @@ -16,7 +15,6 @@ import java.util.logging.Logger; * @author Jo Kristian Bergum */ public class RemoteHealthMetricFetcher extends HttpMetricFetcher { - private static final ObjectMapper jsonMapper = new ObjectMapper(); private final static Logger log = Logger.getLogger(RemoteHealthMetricFetcher.class.getPackage().getName()); private final static String HEALTH_PATH = STATE_PATH + "health"; @@ -56,16 +54,16 @@ public class RemoteHealthMetricFetcher extends HttpMetricFetcher { return HealthMetric.getUnknown("Empty response from status page"); } try { - JsonNode o = jsonMapper.readTree(data); - JsonNode status = o.get("status"); - String code = status.get("code").textValue(); + JSONObject o = new JSONObject(data); + JSONObject status = o.getJSONObject("status"); + String code = status.getString("code"); String message = ""; if (status.has("message")) { - message = status.get("message").textValue(); + message = status.getString("message"); } return HealthMetric.get(code, message); - } catch (IOException e) { + } catch (JSONException e) { log.log(Level.FINE, "Failed to parse json response from metrics page:" + e + ":" + data); return HealthMetric.getUnknown("Not able to parse json from status page"); } diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java index c2935761179..442ebc0d38d 100644 --- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java +++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/RemoteMetricsFetcher.java @@ -4,9 +4,9 @@ package ai.vespa.metricsproxy.service; import ai.vespa.metricsproxy.metric.Metric; import ai.vespa.metricsproxy.metric.Metrics; import ai.vespa.metricsproxy.metric.model.DimensionId; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import java.io.IOException; import java.util.Collections; @@ -23,8 +23,6 @@ import static ai.vespa.metricsproxy.metric.model.DimensionId.toDimensionId; */ public class RemoteMetricsFetcher extends HttpMetricFetcher { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - final static String METRICS_PATH = STATE_PATH + "metrics"; RemoteMetricsFetcher(VespaService service, int port) { @@ -59,21 +57,21 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher { return remoteMetrics; } - private Metrics parse(String data) throws IOException { - JsonNode o = jsonMapper.readTree(data); + private Metrics parse(String data) throws JSONException { + JSONObject o = new JSONObject(data); if (!(o.has("metrics"))) { return new Metrics(); //empty } - JsonNode metrics = o.get("metrics"); - ArrayNode values; + JSONObject metrics = o.getJSONObject("metrics"); + JSONArray values; long timestamp; try { - JsonNode snapshot = metrics.get("snapshot"); - timestamp = (long) snapshot.get("to").doubleValue(); - values = (ArrayNode) metrics.get("values"); - } catch (Exception e) { + JSONObject snapshot = metrics.getJSONObject("snapshot"); + timestamp = (long) snapshot.getDouble("to"); + values = metrics.getJSONArray("values"); + } catch (JSONException e) { // snapshot might not have been produced. Do not throw exception into log return new Metrics(); } @@ -83,29 +81,29 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher { Map<DimensionId, String> noDims = Collections.emptyMap(); Map<String, Map<DimensionId, String>> uniqueDimensions = new HashMap<>(); - for (int i = 0; i < values.size(); i++) { - JsonNode metric = values.get(i); - String name = metric.get("name").textValue(); + for (int i = 0; i < values.length(); i++) { + JSONObject metric = values.getJSONObject(i); + String name = metric.getString("name"); String description = ""; if (metric.has("description")) { - description = metric.get("description").textValue(); + description = metric.getString("description"); } Map<DimensionId, String> dim = noDims; if (metric.has("dimensions")) { - JsonNode dimensions = metric.get("dimensions"); + JSONObject dimensions = metric.getJSONObject("dimensions"); StringBuilder sb = new StringBuilder(); - for (Iterator<?> it = dimensions.fieldNames(); it.hasNext(); ) { + for (Iterator<?> it = dimensions.keys(); it.hasNext(); ) { String k = (String) it.next(); - String v = dimensions.get(k).textValue(); + String v = dimensions.getString(k); sb.append(toDimensionId(k)).append(v); } if ( ! uniqueDimensions.containsKey(sb.toString())) { dim = new HashMap<>(); - for (Iterator<?> it = dimensions.fieldNames(); it.hasNext(); ) { + for (Iterator<?> it = dimensions.keys(); it.hasNext(); ) { String k = (String) it.next(); - String v = dimensions.get(k).textValue(); + String v = dimensions.getString(k); dim.put(toDimensionId(k), v); } uniqueDimensions.put(sb.toString(), Collections.unmodifiableMap(dim)); @@ -113,11 +111,10 @@ public class RemoteMetricsFetcher extends HttpMetricFetcher { dim = uniqueDimensions.get(sb.toString()); } - JsonNode aggregates = metric.get("values"); - for (Iterator<?> it = aggregates.fieldNames(); it.hasNext(); ) { + JSONObject aggregates = metric.getJSONObject("values"); + for (Iterator<?> it = aggregates.keys(); it.hasNext(); ) { String aggregator = (String) it.next(); - Number value = aggregates.get(aggregator).numberValue(); - if (value == null) throw new IllegalArgumentException("Value for aggregator '" + aggregator + "' is missing"); + Number value = (Number) aggregates.get(aggregator); StringBuilder metricName = (new StringBuilder()).append(name).append(".").append(aggregator); m.add(new Metric(metricName.toString(), value, timestamp, dim, description)); } diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java index cf1eac3c691..d7576718e8a 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/application/ApplicationMetricsHandlerTest.java @@ -8,11 +8,13 @@ import ai.vespa.metricsproxy.metric.model.json.GenericApplicationModel; import ai.vespa.metricsproxy.metric.model.json.GenericJsonModel; import ai.vespa.metricsproxy.metric.model.json.GenericMetrics; import ai.vespa.metricsproxy.metric.model.json.GenericService; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.github.tomakehurst.wiremock.junit.WireMockRule; import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import java.util.regex.Pattern; + +import org.json.JSONArray; +import org.json.JSONObject; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; @@ -22,7 +24,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.Map; import java.util.concurrent.Executors; -import java.util.regex.Pattern; import static ai.vespa.metricsproxy.TestUtil.getFileContents; import static ai.vespa.metricsproxy.http.ValuesFetcher.defaultMetricsConsumerId; @@ -48,8 +49,6 @@ import static org.junit.Assert.fail; @SuppressWarnings("UnstableApiUsage") public class ApplicationMetricsHandlerTest { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String HOST = "localhost"; private static final String URI_BASE = "http://" + HOST; private static final String METRICS_V1_URI = URI_BASE + METRICS_V1_PATH; @@ -103,16 +102,16 @@ public class ApplicationMetricsHandlerTest { @Test public void v1_response_contains_values_uri() throws Exception { String response = testDriver.sendRequest(METRICS_V1_URI).readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("resources")); - ArrayNode resources = (ArrayNode) root.get("resources"); - assertEquals(2, resources.size()); + JSONArray resources = root.getJSONArray("resources"); + assertEquals(2, resources.length()); - JsonNode valuesUrl = resources.get(0); - assertEquals(METRICS_VALUES_URI, valuesUrl.get("url").textValue()); - JsonNode prometheusUrl = resources.get(1); - assertEquals(PROMETHEUS_VALUES_URI, prometheusUrl.get("url").textValue()); + JSONObject valuesUrl = resources.getJSONObject(0); + assertEquals(METRICS_VALUES_URI, valuesUrl.getString("url")); + JSONObject prometheusUrl = resources.getJSONObject(1); + assertEquals(PROMETHEUS_VALUES_URI, prometheusUrl.getString("url")); } @Ignore @@ -200,7 +199,7 @@ public class ApplicationMetricsHandlerTest { @Test public void invalid_path_yields_error_response() throws Exception { String response = testDriver.sendRequest(METRICS_V1_URI + "/invalid").readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("error")); } diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java index 379ef04d38d..1c5ce695155 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/metrics/MetricsHandlerTestBase.java @@ -6,9 +6,9 @@ import ai.vespa.metricsproxy.metric.model.json.GenericJsonModel; import ai.vespa.metricsproxy.metric.model.json.GenericMetrics; import ai.vespa.metricsproxy.metric.model.json.GenericService; import ai.vespa.metricsproxy.service.DownService; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; +import org.json.JSONArray; +import org.json.JSONObject; import org.junit.Ignore; import org.junit.Test; @@ -32,8 +32,6 @@ import static org.junit.Assert.fail; */ public abstract class MetricsHandlerTestBase<MODEL> extends HttpHandlerTestBase { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - static String rootUri; static String valuesUri; @@ -58,21 +56,21 @@ public abstract class MetricsHandlerTestBase<MODEL> extends HttpHandlerTestBase @Test public void invalid_path_yields_error_response() throws Exception { String response = testDriver.sendRequest(rootUri + "/invalid").readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("error")); } @Test public void root_response_contains_values_uri() throws Exception { String response = testDriver.sendRequest(rootUri).readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("resources")); - ArrayNode resources = (ArrayNode) root.get("resources"); - assertEquals(1, resources.size()); + JSONArray resources = root.getJSONArray("resources"); + assertEquals(1, resources.length()); - JsonNode valuesUrl = resources.get(0); - assertEquals(valuesUri, valuesUrl.get("url").textValue()); + JSONObject valuesUrl = resources.getJSONObject(0); + assertEquals(valuesUri, valuesUrl.getString("url")); } @Ignore diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java index 89186e63b93..a224c4090b3 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/http/prometheus/PrometheusHandlerTest.java @@ -3,10 +3,9 @@ package ai.vespa.metricsproxy.http.prometheus; import ai.vespa.metricsproxy.http.HttpHandlerTestBase; import ai.vespa.metricsproxy.service.DummyService; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.yahoo.container.jdisc.RequestHandlerTestDriver; +import org.json.JSONArray; +import org.json.JSONObject; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; @@ -23,8 +22,6 @@ import static org.junit.Assert.assertTrue; @SuppressWarnings("UnstableApiUsage") public class PrometheusHandlerTest extends HttpHandlerTestBase { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String V1_URI = URI_BASE + PrometheusHandler.V1_PATH; private static final String VALUES_URI = URI_BASE + PrometheusHandler.VALUES_PATH; @@ -43,14 +40,14 @@ public class PrometheusHandlerTest extends HttpHandlerTestBase { @Test public void v1_response_contains_values_uri() throws Exception { String response = testDriver.sendRequest(V1_URI).readAll(); - JsonNode root = jsonMapper.readTree(response); + JSONObject root = new JSONObject(response); assertTrue(root.has("resources")); - ArrayNode resources = (ArrayNode) root.get("resources"); - assertEquals(1, resources.size()); + JSONArray resources = root.getJSONArray("resources"); + assertEquals(1, resources.length()); - JsonNode valuesUrl = resources.get(0); - assertEquals(VALUES_URI, valuesUrl.get("url").textValue()); + JSONObject valuesUrl = resources.getJSONObject(0); + assertEquals(VALUES_URI, valuesUrl.getString("url")); } @Ignore diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java index c2fc23a878d..e2ad0ccd504 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/node/NodeMetricGathererTest.java @@ -3,9 +3,8 @@ package ai.vespa.metricsproxy.node; import ai.vespa.metricsproxy.metric.model.MetricId; import ai.vespa.metricsproxy.metric.model.MetricsPacket; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; import java.util.ArrayList; @@ -18,12 +17,10 @@ import static org.junit.Assert.assertEquals; */ public class NodeMetricGathererTest { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - @Test - public void testJSONObjectIsCorrectlyConvertedToMetricsPacket() { + public void testJSONObjectIsCorrectlyConvertedToMetricsPacket() throws JSONException { List<MetricsPacket.Builder> builders = new ArrayList<>(); - JsonNode hostLifePacket = generateHostLifePacket(); + JSONObject hostLifePacket = generateHostLifePacket(); NodeMetricGatherer.addObjectToBuilders(builders, hostLifePacket); MetricsPacket packet = builders.remove(0).build(); @@ -35,17 +32,17 @@ public class NodeMetricGathererTest { assertEquals(1l, packet.metrics().get(MetricId.toMetricId("alive"))); } - private JsonNode generateHostLifePacket() { + private JSONObject generateHostLifePacket() throws JSONException { - ObjectNode jsonObject = jsonMapper.createObjectNode(); + JSONObject jsonObject = new JSONObject(); jsonObject.put("status_code", 0); jsonObject.put("status_msg", "OK"); jsonObject.put("timestamp", 123); jsonObject.put("application", "host_life"); - ObjectNode metrics = jsonMapper.createObjectNode(); + JSONObject metrics = new JSONObject(); metrics.put("uptime", 12); metrics.put("alive", 1); - jsonObject.set("metrics", metrics); + jsonObject.put("metrics", metrics); return jsonObject; } } diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java index 70970bfe8da..8d5bba77844 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/rpc/RpcMetricsTest.java @@ -5,18 +5,17 @@ import ai.vespa.metricsproxy.metric.Metric; import ai.vespa.metricsproxy.metric.Metrics; import ai.vespa.metricsproxy.metric.model.ConsumerId; import ai.vespa.metricsproxy.service.VespaService; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.yahoo.jrt.Request; import com.yahoo.jrt.Spec; import com.yahoo.jrt.StringValue; import com.yahoo.jrt.Supervisor; import com.yahoo.jrt.Target; import com.yahoo.jrt.Transport; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.junit.Test; -import java.io.IOException; import java.util.List; import static ai.vespa.metricsproxy.TestUtil.getFileContents; @@ -41,8 +40,6 @@ import static org.junit.Assert.assertTrue; */ public class RpcMetricsTest { - private static final ObjectMapper jsonMapper = new ObjectMapper(); - private static final String METRICS_RESPONSE = getFileContents("metrics-storage-simple.json").trim(); private static final String EXTRA_APP = "extra"; @@ -70,9 +67,9 @@ public class RpcMetricsTest { String allServicesResponse = getMetricsForYamas(ALL_SERVICES, rpcClient).trim(); // Verify that application is used as serviceId, and that metric exists. - JsonNode extraMetrics = findExtraMetricsObject(allServicesResponse); - assertThat(extraMetrics.get("metrics").get("foo.count").intValue(), is(3)); - assertThat(extraMetrics.get("dimensions").get("role").textValue(), is("extra-role")); + JSONObject extraMetrics = findExtraMetricsObject(allServicesResponse); + assertThat(extraMetrics.getJSONObject("metrics").getInt("foo.count"), is(3)); + assertThat(extraMetrics.getJSONObject("dimensions").getString("role"), is("extra-role")); } } } @@ -88,7 +85,7 @@ public class RpcMetricsTest { // Verify that no extra metrics exists String allServicesResponse = getMetricsForYamas(ALL_SERVICES, rpcClient).trim(); - JsonNode extraMetrics = findExtraMetricsObject(allServicesResponse); + JSONObject extraMetrics = findExtraMetricsObject(allServicesResponse); assertEquals(extraMetrics.toString(), "{}"); } } @@ -133,28 +130,28 @@ public class RpcMetricsTest { } } - private static void verifyMetricsFromRpcRequest(VespaService service, RpcClient client) throws IOException { + private static void verifyMetricsFromRpcRequest(VespaService service, RpcClient client) throws JSONException { String jsonResponse = getMetricsForYamas(service.getMonitoringName(), client).trim(); - ArrayNode metrics = (ArrayNode) jsonMapper.readTree(jsonResponse).get("metrics"); - assertThat("Expected 3 metric messages", metrics.size(), is(3)); - for (int i = 0; i < metrics.size() - 1; i++) { // The last "metric message" contains only status code/message - JsonNode jsonObject = metrics.get(i); + JSONArray metrics = new JSONObject(jsonResponse).getJSONArray("metrics"); + assertThat("Expected 3 metric messages", metrics.length(), is(3)); + for (int i = 0; i < metrics.length() - 1; i++) { // The last "metric message" contains only status code/message + JSONObject jsonObject = metrics.getJSONObject(i); assertFalse(jsonObject.has("status_code")); assertFalse(jsonObject.has("status_msg")); - assertThat(jsonObject.get("dimensions").get("foo").textValue(), is("bar")); - assertThat(jsonObject.get("dimensions").get("bar").textValue(), is("foo")); - assertThat(jsonObject.get("dimensions").get("serviceDim").textValue(), is("serviceDimValue")); - assertThat(jsonObject.get("routing").get("yamas").get("namespaces").size(), is(1)); - if (jsonObject.get("metrics").has("foo_count")) { - assertThat(jsonObject.get("metrics").get("foo_count").intValue(), is(1)); - assertThat(jsonObject.get("routing").get("yamas").get("namespaces").get(0).textValue(), is(vespaMetricsConsumerId.id)); + assertThat(jsonObject.getJSONObject("dimensions").getString("foo"), is("bar")); + assertThat(jsonObject.getJSONObject("dimensions").getString("bar"), is("foo")); + assertThat(jsonObject.getJSONObject("dimensions").getString("serviceDim"), is("serviceDimValue")); + assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").length(), is(1)); + if (jsonObject.getJSONObject("metrics").has("foo_count")) { + assertThat(jsonObject.getJSONObject("metrics").getInt("foo_count"), is(1)); + assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").get(0), is(vespaMetricsConsumerId.id)); } else { - assertThat(jsonObject.get("metrics").get("foo.count").intValue(), is(1)); - assertThat(jsonObject.get("routing").get("yamas").get("namespaces").get(0).textValue(), is(CUSTOM_CONSUMER_ID.id)); + assertThat(jsonObject.getJSONObject("metrics").getInt("foo.count"), is(1)); + assertThat(jsonObject.getJSONObject("routing").getJSONObject("yamas").getJSONArray("namespaces").get(0), is(CUSTOM_CONSUMER_ID.id)); } } - verifyStatusMessage(metrics.get(metrics.size() - 1)); + verifyStatusMessage(metrics.getJSONObject(metrics.length() - 1)); } private void verfiyMetricsFromServiceObject(VespaService service) { @@ -169,15 +166,15 @@ public class RpcMetricsTest { assertThat("Metric foo did not contain correct dimension for key = bar", foo.getDimensions().get(toDimensionId("bar")), is("foo")); } - private void verifyMetricsFromRpcRequestForAllServices(RpcClient client) throws IOException { + private void verifyMetricsFromRpcRequestForAllServices(RpcClient client) throws JSONException { // Verify that metrics for all services can be retrieved in one request. String allServicesResponse = getMetricsForYamas(ALL_SERVICES, client).trim(); - ArrayNode allServicesMetrics = (ArrayNode) jsonMapper.readTree(allServicesResponse).get("metrics"); - assertThat(allServicesMetrics.size(), is(5)); + JSONArray allServicesMetrics = new JSONObject(allServicesResponse).getJSONArray("metrics"); + assertThat(allServicesMetrics.length(), is(5)); } @Test - public void testGetAllMetricNames() { + public void testGetAllMetricNames() throws Exception { try (IntegrationTester tester = new IntegrationTester()) { tester.httpServer().setResponse(METRICS_RESPONSE); @@ -208,14 +205,14 @@ public class RpcMetricsTest { invoke(req, rpcClient, false); } - private JsonNode findExtraMetricsObject(String jsonResponse) throws IOException { - ArrayNode metrics = (ArrayNode) jsonMapper.readTree(jsonResponse).get("metrics"); - for (int i = 0; i < metrics.size(); i++) { - JsonNode jsonObject = metrics.get(i); + private JSONObject findExtraMetricsObject(String jsonResponse) throws JSONException { + JSONArray metrics = new JSONObject(jsonResponse).getJSONArray("metrics"); + for (int i = 0; i < metrics.length(); i++) { + JSONObject jsonObject = metrics.getJSONObject(i); assertTrue(jsonObject.has("application")); - if (jsonObject.get("application").textValue().equals(EXTRA_APP)) return jsonObject; + if (jsonObject.getString("application").equals(EXTRA_APP)) return jsonObject; } - return jsonMapper.createObjectNode(); + return new JSONObject(); } private static String getMetricsForYamas(String service, RpcClient client) { @@ -253,12 +250,12 @@ public class RpcMetricsTest { return returnValue; } - private static void verifyStatusMessage(JsonNode jsonObject) { - assertThat(jsonObject.get("status_code").intValue(), is(0)); - assertThat(jsonObject.get("status_msg").textValue(), notNullValue()); - assertThat(jsonObject.get("application").textValue(), notNullValue()); - assertThat(jsonObject.get("routing"), notNullValue()); - assertThat(jsonObject.size(), is(4)); + private static void verifyStatusMessage(JSONObject jsonObject) throws JSONException { + assertThat(jsonObject.getInt("status_code"), is(0)); + assertThat(jsonObject.getString("status_msg"), notNullValue()); + assertThat(jsonObject.getString("application"), notNullValue()); + assertThat(jsonObject.getString("routing"), notNullValue()); + assertThat(jsonObject.length(), is(4)); } } diff --git a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java index 7ff179e5528..0d53f988ac7 100644 --- a/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java +++ b/metrics-proxy/src/test/java/ai/vespa/metricsproxy/service/ContainerServiceTest.java @@ -2,6 +2,7 @@ package ai.vespa.metricsproxy.service; import ai.vespa.metricsproxy.metric.Metric; +import org.json.JSONException; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -36,7 +37,7 @@ public class ContainerServiceTest { } @Test - public void testMultipleQueryDimensions() { + public void testMultipleQueryDimensions() throws JSONException { int count = 0; VespaService service = VespaService.create("service1", "id", httpServer.port()); for (Metric m : service.getMetrics().getMetrics()) { |