From 47f4b66b45250e00260905ac3ec34b9ddb1a5362 Mon Sep 17 00:00:00 2001 From: "Maharajh, Robby (rx2202)" Date: Tue, 2 Jan 2018 13:05:03 -0500 Subject: Add new query format count and support for path/tree Issue-ID: AAI-602 Change-Id: I3e1bac256e679c0466fc3eceb52d440095b272d8 Signed-off-by: Maharajh, Robby (rx2202) --- .../onap/aai/serialization/queryformats/Count.java | 83 ++++++++++++++++ .../aai/serialization/queryformats/Format.java | 7 +- .../serialization/queryformats/FormatFactory.java | 23 +++-- .../serialization/queryformats/FormatMapper.java | 5 +- .../aai/serialization/queryformats/Formatter.java | 83 ++++++++++------ .../onap/aai/serialization/queryformats/IdURL.java | 6 +- .../queryformats/MultiFormatMapper.java | 110 +++++++++++++++++++++ .../aai/serialization/queryformats/PathedURL.java | 6 +- .../aai/serialization/queryformats/RawFormat.java | 30 +++--- .../aai/serialization/queryformats/Resource.java | 6 +- .../AAIFormatQueryResultFormatNotSupported.java | 13 +-- 11 files changed, 296 insertions(+), 76 deletions(-) create mode 100644 aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java create mode 100644 aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java (limited to 'aai-core/src/main/java') diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java new file mode 100644 index 00000000..aea4ba12 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Count.java @@ -0,0 +1,83 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.serialization.queryformats; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.javatuples.Pair; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + +import com.google.gson.JsonObject; + +public class Count implements FormatMapper { + + @Override + public JsonObject formatObject(Object o) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + @SuppressWarnings("unchecked") + List list = (List) o; + + final JsonObject countResult = new JsonObject(); + + list.stream().map(this::getCount) + .filter( Optional>::isPresent ) + .map(Optional>::get) + .collect( Collectors.toConcurrentMap( Pair::getValue0, Pair::getValue1, Long::sum ) ) + .forEach( (k,v) -> countResult.addProperty(k, v) ); + + return countResult; + } + + @Override + public int parallelThreshold() { + return 20; + } + + private Optional> getCount(Object o){ + + Pair pair = null; + + if (o instanceof Vertex) { + Vertex v = (Vertex) o; + pair = Pair.with(v.property(AAIProperties.NODE_TYPE).value().toString(), 1L); + } else if (o instanceof Tree) { + pair = Pair.with("trees", 1L); + } else if (o instanceof Path) { + pair = Pair.with("paths", 1L); + } else if (o instanceof Long) { + pair = Pair.with("count", (Long)o); + } + + if (pair == null) { + return Optional.>empty(); + } + + return Optional.>of(pair); + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java index 2904cce6..04f4d1c1 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Format.java @@ -23,9 +23,12 @@ package org.onap.aai.serialization.queryformats; public enum Format { graphson, - pathed, id, resource, + pathed, + id, + resource, simple, resource_and_url, console, - raw + raw, + count } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java index b19e0c3e..21a7e0fe 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatFactory.java @@ -53,39 +53,42 @@ public class FormatFactory { public Formatter get(Format format, MultivaluedMap params) throws AAIException { - Formatter formattter = null; + Formatter formatter = null; switch (format) { case graphson : - formattter = new Formatter(inject(new GraphSON(), params)); + formatter = new Formatter(inject(new GraphSON(), params)); break; case pathed : - formattter = new Formatter(inject(new PathedURL(loader, urlBuilder), params)); + formatter = new Formatter(inject(new PathedURL(loader, urlBuilder), params)); break; case id : - formattter = new Formatter(inject(new IdURL(loader, urlBuilder), params)); + formatter = new Formatter(inject(new IdURL(loader, urlBuilder), params)); break; case resource : - formattter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder), params).build()); + formatter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder), params).build()); break; case resource_and_url : - formattter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder).includeUrl(), params).build()); + formatter = new Formatter(inject(new Resource.Builder(loader, serializer, urlBuilder).includeUrl(), params).build()); break; case raw : - formattter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder), params).build()); + formatter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder), params).build()); break; case simple : - formattter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder).depth(0).modelDriven(), params).build()); + formatter = new Formatter(inject(new RawFormat.Builder(loader, serializer, urlBuilder).depth(0).modelDriven(), params).build()); break; case console : - formattter = new Formatter(inject(new Console(), params)); + formatter = new Formatter(inject(new Console(), params)); + break; + case count : + formatter = new Formatter(inject(new Count(), params)); break; default : break; } - return formattter; + return formatter; } private T inject (T obj, MultivaluedMap params) throws QueryParamInjectionException { diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java index fb822dd9..27d204a6 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/FormatMapper.java @@ -21,12 +21,13 @@ */ package org.onap.aai.serialization.queryformats; -import com.google.gson.JsonObject; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; +import com.google.gson.JsonObject; public interface FormatMapper { - public JsonObject formatObject(Object v) throws AAIFormatVertexException; + public JsonObject formatObject(Object o) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported; public int parallelThreshold(); } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java index 50042b76..b145d423 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Formatter.java @@ -21,16 +21,18 @@ */ package org.onap.aai.serialization.queryformats; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Stream; public class Formatter { @@ -38,43 +40,60 @@ public class Formatter { protected JsonParser parser = new JsonParser(); protected final FormatMapper format; - public Formatter (FormatMapper format) { + + public Formatter(FormatMapper format) { this.format = format; } - - public JsonObject output(List vertices) { + + public JsonObject output(List queryResults) { + Stream stream = null; JsonObject result = new JsonObject(); JsonArray body = new JsonArray(); - if (vertices.size() >= format.parallelThreshold()) { - stream = vertices.parallelStream(); - } else { - stream = vertices.stream(); - } - final boolean isParallel = stream.isParallel(); - stream.map(v -> { + + if (this.format instanceof Count) { + JsonObject countResult; try { - return Optional.of(format.formatObject(v)); - } catch (AAIFormatVertexException e) { - LOGGER.warn("Failed to format vertex, returning a partial list", e); + countResult = format.formatObject(queryResults); + body.add(countResult); + } catch (Exception e) { + LOGGER.warn("Failed to format result type of the query", e); } + } else { + if (queryResults.size() >= format.parallelThreshold()) { + stream = queryResults.parallelStream(); + } else { + stream = queryResults.stream(); + } + + final boolean isParallel = stream.isParallel(); + + stream.map(o -> { + try { + return Optional.of(format.formatObject(o)); + } catch (AAIFormatVertexException e) { + LOGGER.warn("Failed to format vertex, returning a partial list", e); + } catch (AAIFormatQueryResultFormatNotSupported e) { + LOGGER.warn("Failed to format result type of the query", e); + } - return Optional.empty(); - }).forEach(obj -> { - if (obj.isPresent()) { - if (isParallel) { - synchronized (body) { - body.add(obj.get()); + return Optional.empty(); + }) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(json -> { + if (isParallel) { + synchronized (body) { + body.add(json); + } + } else { + body.add(json); } - } else { - body.add(obj.get()); - } - } - }); - + }); + + } result.add("results", body); - return result.getAsJsonObject(); } - + } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java index 320cd616..4395c8c9 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/IdURL.java @@ -32,7 +32,7 @@ import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; -public class IdURL implements FormatMapper { +public class IdURL extends MultiFormatMapper { private final UrlBuilder urlBuilder; private final JsonParser parser; @@ -50,8 +50,8 @@ public class IdURL implements FormatMapper { } @Override - public JsonObject formatObject(Object input) throws AAIFormatVertexException { - Vertex v = (Vertex)input; + protected JsonObject getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + try { final Introspector searchResult = this.loader.introspectorFromName("result-data"); diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java new file mode 100644 index 00000000..e4b5fc17 --- /dev/null +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/MultiFormatMapper.java @@ -0,0 +1,110 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. + */ +package org.onap.aai.serialization.queryformats; + +import java.util.Iterator; +import java.util.List; + +import org.apache.tinkerpop.gremlin.process.traversal.Path; +import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatQueryResultFormatNotSupported; +import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +public abstract class MultiFormatMapper implements FormatMapper { + + @Override + public JsonObject formatObject(Object input) throws AAIFormatVertexException, AAIFormatQueryResultFormatNotSupported { + if (input instanceof Vertex) { + return this.getJsonFromVertex((Vertex) input); + } else if (input instanceof Tree) { + return this.getJsonFomTree((Tree) input); + } else if (input instanceof Path) { + return this.getJsonFromPath((Path) input); + } else { + throw new AAIFormatQueryResultFormatNotSupported(); + } + } + + protected abstract JsonObject getJsonFromVertex(Vertex input) throws AAIFormatVertexException; + + protected JsonObject getJsonFromPath(Path input) throws AAIFormatVertexException { + List path = input.objects(); + + JsonObject jo = new JsonObject(); + JsonArray ja = new JsonArray(); + + for (Object o : path) { + if (o instanceof Vertex) { + ja.add(this.getJsonFromVertex((Vertex)o)); + } + } + + jo.add("path", ja); + return jo; + } + + protected JsonObject getJsonFomTree(Tree tree) throws AAIFormatVertexException { + + if (tree.isEmpty()) { + return new JsonObject(); + } + + JsonObject t = new JsonObject(); + JsonArray ja = this.getNodesArray(tree); + if (ja.size() > 0) { + t.add("nodes", ja); + } + + return t; + } + + private JsonArray getNodesArray (Tree tree) throws AAIFormatVertexException { + + JsonArray nodes = new JsonArray(); + Iterator it = tree.keySet().iterator(); + + while (it.hasNext()) { + Object o = it.next(); + JsonObject me = new JsonObject(); + if (o instanceof Vertex) { + me = this.getJsonFromVertex((Vertex) o); + } + JsonArray ja = this.getNodesArray((Tree) tree.get(o)); + if (ja.size() > 0) { + me.add("nodes", ja); + } + nodes.add(me); + } + return nodes; + } + + + @Override + public int parallelThreshold() { + return 100; + } + +} diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java index 8b9d5058..759f9c50 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/PathedURL.java @@ -32,7 +32,7 @@ import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; -public final class PathedURL implements FormatMapper { +public final class PathedURL extends MultiFormatMapper { private final UrlBuilder urlBuilder; private final JsonParser parser; @@ -50,8 +50,8 @@ public final class PathedURL implements FormatMapper { } @Override - public JsonObject formatObject(Object input) throws AAIFormatVertexException { - Vertex v = (Vertex)input; + protected JsonObject getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + try { final Introspector searchResult = this.loader.introspectorFromName("result-data"); diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java index 3477a748..425c6edf 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/RawFormat.java @@ -42,7 +42,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; -public class RawFormat implements FormatMapper { +public class RawFormat extends MultiFormatMapper { protected JsonParser parser = new JsonParser(); protected final DBSerializer serializer; protected final Loader loader; @@ -57,20 +57,6 @@ public class RawFormat implements FormatMapper { this.nodesOnly = builder.isNodesOnly(); } - @Override - public JsonObject formatObject(Object input) throws AAIFormatVertexException { - Vertex v = (Vertex)input; - JsonObject json = new JsonObject(); - json.addProperty("id", v.id().toString()); - json.addProperty("node-type", v.value(AAIProperties.NODE_TYPE)); - json.addProperty("url", this.urlBuilder.pathed(v)); - json.add("properties", this.createPropertiesObject(v)); - if (!nodesOnly) { - json.add("related-to", this.createRelationshipObject(v)); - } - return json; - } - @Override public int parallelThreshold() { return 100; @@ -200,4 +186,18 @@ public class RawFormat implements FormatMapper { } } } + + @Override + protected JsonObject getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + + JsonObject json = new JsonObject(); + json.addProperty("id", v.id().toString()); + json.addProperty("node-type", v.value(AAIProperties.NODE_TYPE)); + json.addProperty("url", this.urlBuilder.pathed(v)); + json.add("properties", this.createPropertiesObject(v)); + if (!nodesOnly) { + json.add("related-to", this.createRelationshipObject(v)); + } + return json; + } } diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java index 649971be..429530c8 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/Resource.java @@ -40,7 +40,7 @@ import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -public class Resource implements FormatMapper { +public class Resource extends MultiFormatMapper { private final Loader loader; private final DBSerializer serializer; @@ -60,8 +60,8 @@ public class Resource implements FormatMapper { } @Override - public JsonObject formatObject(Object input) throws AAIFormatVertexException { - Vertex v = (Vertex)input; + protected JsonObject getJsonFromVertex(Vertex v) throws AAIFormatVertexException { + JsonObject json = new JsonObject(); if (this.includeUrl) { diff --git a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatQueryResultFormatNotSupported.java b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatQueryResultFormatNotSupported.java index 726116a0..8d8e6835 100644 --- a/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatQueryResultFormatNotSupported.java +++ b/aai-core/src/main/java/org/onap/aai/serialization/queryformats/exceptions/AAIFormatQueryResultFormatNotSupported.java @@ -1,23 +1,24 @@ -/*- +/** * ============LICENSE_START======================================================= * org.onap.aai * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Copyright © 2017 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * + * + * http://www.apache.org/licenses/LICENSE-2.0 + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= + * + * ECOMP is a trademark and service mark of AT&T Intellectual Property. */ - package org.onap.aai.serialization.queryformats.exceptions; public class AAIFormatQueryResultFormatNotSupported extends Exception { -- cgit 1.2.3-korg