Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 489DD200BCE for ; Fri, 2 Dec 2016 12:32:27 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 477C0160B16; Fri, 2 Dec 2016 11:32:27 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id D598F160B3D for ; Fri, 2 Dec 2016 12:32:22 +0100 (CET) Received: (qmail 29233 invoked by uid 500); 2 Dec 2016 11:32:22 -0000 Mailing-List: contact commits-help@tinkerpop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tinkerpop.apache.org Delivered-To: mailing list commits@tinkerpop.apache.org Received: (qmail 28639 invoked by uid 99); 2 Dec 2016 11:32:21 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 02 Dec 2016 11:32:21 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 7ED5EF2131; Fri, 2 Dec 2016 11:32:21 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: spmallette@apache.org To: commits@tinkerpop.apache.org Date: Fri, 02 Dec 2016 11:32:45 -0000 Message-Id: <436d9934351d4b8cb05194f0d066e30a@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [25/50] tinkerpop git commit: TINKERPOP-1562 Added gremlin-console plugins under the new model. archived-at: Fri, 02 Dec 2016 11:32:27 -0000 TINKERPOP-1562 Added gremlin-console plugins under the new model. Had to rework the PluggedIn adapters a bit so that they could better handle Console environment variable.s Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/a91fb80e Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/a91fb80e Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/a91fb80e Branch: refs/heads/TINKERPOP-1562 Commit: a91fb80e64ceb2e5c97b5f8c2ef20205d075ec18 Parents: bb5b47d Author: Stephen Mallette Authored: Tue Nov 22 16:35:16 2016 -0500 Committer: Stephen Mallette Committed: Fri Dec 2 06:28:51 2016 -0500 ---------------------------------------------------------------------- .../tinkerpop/gremlin/console/Console.groovy | 4 +- .../console/jsr223/GephiRemoteAcceptor.groovy | 372 +++++++++++++++++++ .../gremlin/console/plugin/PluggedIn.groovy | 14 +- .../groovy/plugin/DriverGremlinPlugin.java | 2 + .../groovy/plugin/DriverRemoteAcceptor.java | 2 + .../groovy/plugin/GephiGremlinPlugin.java | 1 + .../groovy/plugin/UtilitiesGremlinPlugin.java | 1 + .../console/jsr223/DriverGremlinPlugin.java | 106 ++++++ .../console/jsr223/DriverRemoteAcceptor.java | 238 ++++++++++++ .../console/jsr223/GephiGremlinPlugin.java | 45 +++ .../console/jsr223/UtilitiesGremlinPlugin.java | 106 ++++++ ...pache.tinkerpop.gremlin.jsr223.GremlinPlugin | 3 + .../jsr223/UtilitiesGremlinPluginScript.groovy | 52 +++ .../groovy/plugin/GremlinPluginAdapterTest.java | 5 +- 14 files changed, 940 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/Console.groovy ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/Console.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/Console.groovy index cb6e90f..d39e085 100644 --- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/Console.groovy +++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/Console.groovy @@ -131,9 +131,9 @@ class Console { def pluggedIn if (Mediator.useV3d3) { - pluggedIn = new PluggedIn(new PluggedIn.GremlinPluginAdapter(plugin), groovy, io, false) + pluggedIn = new PluggedIn(new PluggedIn.GremlinPluginAdapter((org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin) plugin, groovy, io), groovy, io, false) } else { - pluggedIn = new PluggedIn(plugin, groovy, io, false) + pluggedIn = new PluggedIn((GremlinPlugin) plugin, groovy, io, false) } mediator.availablePlugins.put(plugin.class.name, pluggedIn) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptor.groovy ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptor.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptor.groovy new file mode 100644 index 0000000..dbc1156 --- /dev/null +++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/jsr223/GephiRemoteAcceptor.groovy @@ -0,0 +1,372 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.console.jsr223 + +import groovy.json.JsonOutput +import groovy.json.JsonSlurper +import groovy.transform.CompileStatic +import org.apache.http.client.methods.CloseableHttpResponse +import org.apache.http.client.methods.HttpUriRequest +import org.apache.http.client.methods.RequestBuilder +import org.apache.http.entity.StringEntity +import org.apache.http.impl.client.CloseableHttpClient +import org.apache.http.impl.client.HttpClients +import org.apache.http.util.EntityUtils +import org.apache.tinkerpop.gremlin.console.plugin.GephiTraversalVisualizationStrategy +import org.apache.tinkerpop.gremlin.jsr223.console.RemoteAcceptor +import org.apache.tinkerpop.gremlin.jsr223.console.RemoteException +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource +import org.apache.tinkerpop.gremlin.structure.Edge +import org.apache.tinkerpop.gremlin.structure.Graph +import org.apache.tinkerpop.gremlin.structure.Vertex +import org.codehaus.groovy.tools.shell.Groovysh +import org.codehaus.groovy.tools.shell.IO + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + * @author Randall Barnhart (randompi@gmail.com) + */ +class GephiRemoteAcceptor implements RemoteAcceptor { + + private String host = "localhost" + private int port = 8080 + private String workspace = "workspace1" + + private final Groovysh shell + private final IO io + + private final Random rand = new Random(); + boolean traversalSubmittedForViz = false + long vizStepDelay + private float[] vizStartRGBColor + private float[] vizDefaultRGBColor + private char vizColorToFade + private float vizColorFadeRate + private float vizStartSize + private float vizSizeDecrementRate + private Map vertexAttributes = [:] + + private CloseableHttpClient httpclient = HttpClients.createDefault(); + + public GephiRemoteAcceptor(final Groovysh shell, final IO io) { + this.shell = shell + this.io = io + + // traversal visualization defaults + vizStepDelay = 1000; // 1 second pause between viz of steps + vizStartRGBColor = [0.0f, 1.0f, 0.5f] // light aqua green + vizDefaultRGBColor = [0.6f, 0.6f, 0.6f] // light grey + vizColorToFade = 'g' // will fade so blue is strongest + vizColorFadeRate = 0.7 // the multiplicative rate to fade visited vertices + vizStartSize = 10 + vizSizeDecrementRate = 0.33f + } + + @Override + connect(final List args) throws RemoteException { + if (args.size() >= 1) + workspace = args[0] + + if (args.size() >= 2) + host = args[1] + + if (args.size() >= 3) { + try { + port = Integer.parseInt(args[2]) + } catch (Exception ex) { + throw new RemoteException("Port must be an integer value") + } + } + + def vizConfig = " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " + + "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate, startSize:$vizStartSize," + + "sizeDecrementRate:$vizSizeDecrementRate" + + return "Connection to Gephi - http://$host:$port/$workspace" + vizConfig + } + + @Override + Object configure(final List args) throws RemoteException { + if (args.size() < 2) + throw new RemoteException("Invalid config arguments - check syntax") + + if (args[0] == "host") + host = args[1] + else if (args[0] == "port") { + try { + port = Integer.parseInt(args[1]) + } catch (Exception ignored) { + throw new RemoteException("Port must be an integer value") + } + } else if (args[0] == "workspace") + workspace = args[1] + else if (args[0] == "stepDelay") + parseVizStepDelay(args[1]) + else if (args[0] == "startRGBColor") + parseVizStartRGBColor(args[1]) + else if (args[0] == "colorToFade") + parseVizColorToFade(args[1]) + else if (args[0] == "colorFadeRate") + parseVizColorFadeRate(args[1]) + else if (args[0] == "sizeDecrementRate") + parseVizSizeDecrementRate(args[1]) + else if (args[0] == "startSize") + parseVizStartSize(args[1]) + else if (args[0] == "visualTraversal") { + def graphVar = shell.interp.context.getVariable(args[1]) + if (!(graphVar instanceof Graph)) + throw new RemoteException("Invalid argument to 'visualTraversal' - first parameter must be a Graph instance") + + def gVar = args.size() == 3 ? args[2] : "vg" + def theG = GraphTraversalSource.build().with(new GephiTraversalVisualizationStrategy(this)).create(graphVar) + shell.interp.context.setVariable(gVar, theG) + } else + throw new RemoteException("Invalid config arguments - check syntax") + + return "Connection to Gephi - http://$host:$port/$workspace" + + " with stepDelay:$vizStepDelay, startRGBColor:$vizStartRGBColor, " + + "colorToFade:$vizColorToFade, colorFadeRate:$vizColorFadeRate, startSize:$vizStartSize," + + "sizeDecrementRate:$vizSizeDecrementRate" + } + + @Override + @CompileStatic + Object submit(final List args) throws RemoteException { + final String line = String.join(" ", args) + if (line.trim() == "clear") { + clearGraph() + io.out.println("Gephi workspace cleared") + return + } + + // need to clear the vertex attributes + vertexAttributes.clear() + + // this tells the GraphTraversalVisualizationStrategy that if the line eval's to a traversal it should + // try to visualize it + traversalSubmittedForViz = true + + // get the colors/sizes back to basics before trying visualize + resetColorsSizes() + + final Object o = shell.execute(line) + if (o instanceof Graph) { + clearGraph() + def graph = (Graph) o + def g = graph.traversal() + g.V().sideEffect { addVertexToGephi(g, it.get()) }.iterate() + } + + traversalSubmittedForViz = false + } + + @Override + void close() throws IOException { + httpclient.close() + } + + /** + * Visits the last set of vertices traversed and degrades their color and size. + */ + def updateVisitedVertices(def List except = []) { + vertexAttributes.keySet().findAll{ vertexId -> !except.contains(vertexId) }.each { String vertexId -> + def attrs = vertexAttributes[vertexId] + float currentColor = attrs.color + currentColor *= vizColorFadeRate + + int currentSize = attrs["size"] + currentSize = Math.max(vizStartSize, currentSize - (currentSize * vizSizeDecrementRate)) + + vertexAttributes.get(vertexId).color = currentColor + vertexAttributes.get(vertexId).size = currentSize + + changeVertexAttributes(vertexId) + } + } + + def changeVertexAttributes(def String vertexId) { + def props = [:] + props.put(vizColorToFade.toString(), vertexAttributes[vertexId].color) + props.put("size", vertexAttributes[vertexId].size) + updateGephiGraph([cn: [(vertexId): props]]) + } + + /** + * Visit a vertex traversed and initialize its color and size. + */ + def visitVertexInGephi(def Vertex v) { + def props = [:] + props.put('r', vizStartRGBColor[0]) + props.put('g', vizStartRGBColor[1]) + props.put('b', vizStartRGBColor[2]) + props.put('size', vizStartSize * 2.5) + props.put('visited', 1) + + updateGephiGraph([cn: [(v.id().toString()): props]]) + + vertexAttributes[v.id().toString()] = [color: vizStartRGBColor[fadeColorIndex()], size: vizStartSize * 2.5, touch: 1] + } + + def fadeColorIndex() { + if (vizColorToFade == 'r') + return 0 + else if (vizColorToFade == 'g') + return 1 + else if (vizColorToFade == 'b') + return 2 + } + + def addVertexToGephi(def GraphTraversalSource g, def Vertex v, def boolean ignoreEdges = false) { + // grab the first property value from the strategies of values + def props = g.V(v).valueMap().next().collectEntries { kv -> [(kv.key): kv.value[0]] } + props << [label: v.label()] + props.put('r', vizDefaultRGBColor[0]) + props.put('g', vizDefaultRGBColor[1]) + props.put('b', vizDefaultRGBColor[2]) + props.put('x', rand.nextFloat()) + props.put('y', rand.nextFloat()) + props.put('size', 10) + props.put('visited', 0) + + // only add if it does not exist in graph already + if (!getFromGephiGraph([operation: "getNode", id: v.id().toString()]).isPresent()) + updateGephiGraph([an: [(v.id().toString()): props]]) + + if (!ignoreEdges) { + g.V(v).outE().sideEffect { + addEdgeToGephi(g, it.get()) + }.iterate() + } + } + + @CompileStatic + def addEdgeToGephi(def GraphTraversalSource g, def Edge e) { + def props = g.E(e).valueMap().next() + props.put('label', e.label()) + props.put('source', e.outVertex().id().toString()) + props.put('target', e.inVertex().id().toString()) + props.put('directed', true) + props.put('visited', 0) + + // make sure the in vertex is there but don't add its edges - that will happen later as we are looping + // all vertices in the graph + addVertexToGephi(g, e.inVertex(), true) + + // both vertices are definitely there now, so add the edge + updateGephiGraph([ae: [(e.id().toString()): props]]) + } + + def clearGraph() { + updateGephiGraph([dn: [filter: "ALL"]]) + } + + def resetColorsSizes() { + updateGephiGraph([cn: [filter: [nodeAttribute: [attribute: "visited", value: 1]], + attributes: [size: 1, r: vizDefaultRGBColor[0], g: vizDefaultRGBColor[1], b: vizDefaultRGBColor[2]]]]) + updateGephiGraph([ce: [filter: [edgeAttribute: [attribute: "visited", value: 1]], + attributes: [size: 1, r: vizDefaultRGBColor[0], g: vizDefaultRGBColor[1], b: vizDefaultRGBColor[2]]]]) + } + + def getFromGephiGraph(def Map queryArgs) { + def requestBuilder = RequestBuilder.get("http://$host:$port/$workspace") + queryArgs.each { requestBuilder = requestBuilder.addParameter(it.key, it.value) } + + def httpResp = makeRequest(requestBuilder.build()) + def resp = EntityUtils.toString(httpResp.entity) + + // gephi streaming plugin does not set the content type or respect the Accept header - treat as text + if (resp.isEmpty()) + return Optional.empty() + else + return Optional.of(new JsonSlurper().parseText(resp)) + } + + def updateGephiGraph(def Map postBody) { + def requestBuilder = RequestBuilder.post("http://$host:$port/$workspace") + .addParameter("format", "JSON") + .addParameter("operation", "updateGraph") + .setEntity(new StringEntity(JsonOutput.toJson(postBody))) + EntityUtils.consume(makeRequest(requestBuilder.build()).entity) + } + + private CloseableHttpResponse makeRequest(HttpUriRequest request) { + def httpResp = httpclient.execute(request) + if (httpResp.getStatusLine().getStatusCode() == 200) { + return httpResp + } else { + def resp = EntityUtils.toString(httpResp.entity) + throw new RuntimeException("Unsuccessful request to Gephi - [${httpResp.getStatusLine().getStatusCode()}] ${httpResp.getStatusLine().getReasonPhrase()} - $resp") + } + } + + @Override + public String toString() { + return "Gephi - [$workspace]" + } + + private void parseVizStepDelay(String arg) { + try { + vizStepDelay = Long.parseLong(arg) + } catch (Exception ignored) { + throw new RemoteException("The stepDelay must be a long value") + } + } + + private void parseVizStartRGBColor(String arg) { + try { + vizStartRGBColor = arg[1..-2].tokenize(',')*.toFloat() + assert (vizStartRGBColor.length == 3) + } catch (Exception ignored) { + throw new RemoteException("The vizStartRGBColor must be an array of 3 float values, e.g. [0.0,1.0,0.5]") + } + } + + private void parseVizColorToFade(String arg) { + try { + vizColorToFade = arg.charAt(0).toLowerCase(); + assert (vizColorToFade == 'r' || vizColorToFade == 'g' || vizColorToFade == 'b') + } catch (Exception ignored) { + throw new RemoteException("The vizColorToFade must be one character value among: r, g, b, R, G, B") + } + } + + private void parseVizColorFadeRate(String arg) { + try { + vizColorFadeRate = Float.parseFloat(arg) + } catch (Exception ignored) { + throw new RemoteException("The colorFadeRate must be a float value") + } + } + + private void parseVizSizeDecrementRate(String arg) { + try { + vizSizeDecrementRate = Float.parseFloat(arg) + } catch (Exception ignored) { + throw new RemoteException("The sizeDecrementRate must be a float value") + } + } + + private void parseVizStartSize(String arg) { + try { + vizStartSize = Float.parseFloat(arg) + } catch (Exception ignored) { + throw new RemoteException("The startSize must be a float value") + } + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/PluggedIn.groovy ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/PluggedIn.groovy b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/PluggedIn.groovy index dc63a2f..7a08a9d 100644 --- a/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/PluggedIn.groovy +++ b/gremlin-console/src/main/groovy/org/apache/tinkerpop/gremlin/console/plugin/PluggedIn.groovy @@ -68,9 +68,13 @@ class PluggedIn { public static class GremlinPluginAdapter implements GremlinPlugin { org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin corePlugin + private final Groovysh shell + private final IO io - public GremlinPluginAdapter(final org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin corePlugin) { + public GremlinPluginAdapter(final org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin corePlugin, final Groovysh shell, final IO io) { this.corePlugin = corePlugin + this.shell = shell + this.io = io } @Override @@ -103,11 +107,11 @@ class PluggedIn { @Override Optional remoteAcceptor() { // find a consoleCustomizer if available - if (!corePlugin.getCustomizers("gremlin-groovy").any{ it instanceof ConsoleCustomizer }) - Optional.empty() + if (!corePlugin.getCustomizers("gremlin-groovy").isPresent() || !corePlugin.getCustomizers("gremlin-groovy").get().any{ it instanceof ConsoleCustomizer }) + return Optional.empty() - ConsoleCustomizer customizer = (ConsoleCustomizer) corePlugin.getCustomizers("gremlin-groovy").find{ it instanceof ConsoleCustomizer } - return Optional.of(new RemoteAcceptorAdapter(customizer.remoteAcceptor)) + ConsoleCustomizer customizer = (ConsoleCustomizer) corePlugin.getCustomizers("gremlin-groovy").get().find{ it instanceof ConsoleCustomizer } + return Optional.of(new RemoteAcceptorAdapter(customizer.getRemoteAcceptor([(ConsoleCustomizer.ENV_CONSOLE_SHELL): shell, (ConsoleCustomizer.ENV_CONSOLE_IO): io]))) } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverGremlinPlugin.java index 2c52bd5..2f8fc75 100644 --- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverGremlinPlugin.java +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverGremlinPlugin.java @@ -35,7 +35,9 @@ import java.util.Set; /** * @author Stephen Mallette (http://stephen.genoprime.com) + * @deprecated As of release 3.2.4, replaced by {@link org.apache.tinkerpop.gremlin.console.jsr223.DriverGremlinPlugin}. */ +@Deprecated public class DriverGremlinPlugin extends AbstractGremlinPlugin { private static final Set IMPORTS = new HashSet() {{ http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java index c346540..80e8194 100644 --- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/DriverRemoteAcceptor.java @@ -50,7 +50,9 @@ import java.util.stream.Stream; * * @author Stephen Mallette (http://stephen.genoprime.com) * @author Marko A. Rodriguez (http://markorodriguez.com) + * @deprecated As of release 3.2.4, replaced by {@link org.apache.tinkerpop.gremlin.console.jsr223.DriverRemoteAcceptor}. */ +@Deprecated public class DriverRemoteAcceptor implements RemoteAcceptor { public static final int NO_TIMEOUT = 0; http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiGremlinPlugin.java index 6977aa8..df0541f 100644 --- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiGremlinPlugin.java +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GephiGremlinPlugin.java @@ -29,6 +29,7 @@ import java.util.Optional; /** * @author Stephen Mallette (http://stephen.genoprime.com) + * @deprecated As of release 3.2.4, replaced by {@link org.apache.tinkerpop.gremlin.console.jsr223.GephiGremlinPlugin}. */ public class GephiGremlinPlugin extends AbstractGremlinPlugin { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPlugin.java index 59c2b1a..d1c853d 100644 --- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPlugin.java +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/UtilitiesGremlinPlugin.java @@ -34,6 +34,7 @@ import java.util.Set; /** * @author Stephen Mallette (http://stephen.genoprime.com) + * @deprecated As of release 3.2.4, replaced by {@link org.apache.tinkerpop.gremlin.console.jsr223.UtilitiesGremlinPlugin}. */ public class UtilitiesGremlinPlugin extends AbstractGremlinPlugin { http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java new file mode 100644 index 0000000..89cec10 --- /dev/null +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.console.jsr223; + +import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.Cluster; +import org.apache.tinkerpop.gremlin.driver.Host; +import org.apache.tinkerpop.gremlin.driver.LoadBalancingStrategy; +import org.apache.tinkerpop.gremlin.driver.MessageSerializer; +import org.apache.tinkerpop.gremlin.driver.Result; +import org.apache.tinkerpop.gremlin.driver.ResultSet; +import org.apache.tinkerpop.gremlin.driver.Tokens; +import org.apache.tinkerpop.gremlin.driver.exception.ConnectionException; +import org.apache.tinkerpop.gremlin.driver.exception.ResponseException; +import org.apache.tinkerpop.gremlin.driver.message.RequestMessage; +import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage; +import org.apache.tinkerpop.gremlin.driver.message.ResponseResult; +import org.apache.tinkerpop.gremlin.driver.message.ResponseStatus; +import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode; +import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteConnection; +import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal; +import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversalSideEffects; +import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0; +import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0; +import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0; +import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0; +import org.apache.tinkerpop.gremlin.driver.ser.GryoLiteMessageSerializerV1d0; +import org.apache.tinkerpop.gremlin.driver.ser.GryoMessageSerializerV1d0; +import org.apache.tinkerpop.gremlin.driver.ser.JsonBuilderGryoSerializer; +import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer; +import org.apache.tinkerpop.gremlin.driver.ser.SerTokens; +import org.apache.tinkerpop.gremlin.driver.ser.SerializationException; +import org.apache.tinkerpop.gremlin.driver.ser.Serializers; +import org.apache.tinkerpop.gremlin.jsr223.AbstractGremlinPlugin; +import org.apache.tinkerpop.gremlin.jsr223.DefaultImportCustomizer; +import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer; +import org.apache.tinkerpop.gremlin.jsr223.console.ConsoleCustomizer; +import org.codehaus.groovy.tools.shell.Groovysh; + +import java.util.Map; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class DriverGremlinPlugin extends AbstractGremlinPlugin { + + private static final String NAME = "tinkerpop.server"; + + private static final ImportCustomizer imports = DefaultImportCustomizer.build() + .addClassImports(Cluster.class, + Client.class, + Host.class, + LoadBalancingStrategy.class, + MessageSerializer.class, + Result.class, + ResultSet.class, + Tokens.class, + ConnectionException.class, + ResponseException.class, + RequestMessage.class, + ResponseMessage.class, + ResponseResult.class, + ResponseStatus.class, + ResponseStatusCode.class, + GraphSONMessageSerializerGremlinV1d0.class, + GraphSONMessageSerializerGremlinV2d0.class, + GraphSONMessageSerializerV1d0.class, + GraphSONMessageSerializerV2d0.class, + GryoLiteMessageSerializerV1d0.class, + GryoMessageSerializerV1d0.class, + JsonBuilderGryoSerializer.class, + MessageTextSerializer.class, + SerializationException.class, + Serializers.class, + SerTokens.class, + DriverRemoteConnection.class, + DriverRemoteTraversal.class, + DriverRemoteTraversalSideEffects.class).create(); + + public DriverGremlinPlugin() { + super(NAME, imports, new DriverConsoleCustomizer()); + } + + private static class DriverConsoleCustomizer implements ConsoleCustomizer { + @Override + public org.apache.tinkerpop.gremlin.jsr223.console.RemoteAcceptor getRemoteAcceptor(final Map environment) { + return new DriverRemoteAcceptor((Groovysh) environment.get(ConsoleCustomizer.ENV_CONSOLE_SHELL)); + } + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java new file mode 100644 index 0000000..93ac184 --- /dev/null +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverRemoteAcceptor.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.console.jsr223; + +import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.tinkerpop.gremlin.driver.Client; +import org.apache.tinkerpop.gremlin.driver.Cluster; +import org.apache.tinkerpop.gremlin.driver.Result; +import org.apache.tinkerpop.gremlin.driver.ResultSet; +import org.apache.tinkerpop.gremlin.driver.exception.ResponseException; +import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode; +import org.apache.tinkerpop.gremlin.jsr223.console.RemoteAcceptor; +import org.apache.tinkerpop.gremlin.jsr223.console.RemoteException; +import org.apache.tinkerpop.gremlin.structure.util.ElementHelper; +import org.codehaus.groovy.tools.shell.Groovysh; + +import javax.security.sasl.SaslException; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Stream; + +/** + * A {@link RemoteAcceptor} that takes input from the console and sends it to Gremlin Server over the standard + * Java driver. + * + * @author Stephen Mallette (http://stephen.genoprime.com) + * @author Marko A. Rodriguez (http://markorodriguez.com) + */ +public class DriverRemoteAcceptor implements RemoteAcceptor { + public static final int NO_TIMEOUT = 0; + + private Cluster currentCluster; + private Client currentClient; + private int timeout = NO_TIMEOUT; + private Map aliases = new HashMap<>(); + private Optional session = Optional.empty(); + + private static final String TOKEN_RESET = "reset"; + private static final String TOKEN_SHOW = "show"; + + /** + * @deprecated As of 3.1.3, replaced by "none" option + */ + @Deprecated + private static final String TOKEN_MAX = "max"; + private static final String TOKEN_NONE = "none"; + private static final String TOKEN_TIMEOUT = "timeout"; + private static final String TOKEN_ALIAS = "alias"; + private static final String TOKEN_SESSION = "session"; + private static final String TOKEN_SESSION_MANAGED = "session-managed"; + private static final List POSSIBLE_TOKENS = Arrays.asList(TOKEN_TIMEOUT, TOKEN_ALIAS); + + private final Groovysh shell; + + public DriverRemoteAcceptor(final Groovysh shell) { + this.shell = shell; + } + + @Override + public Object connect(final List args) throws RemoteException { + if (args.size() < 1) throw new RemoteException("Expects the location of a configuration file as an argument"); + + try { + this.currentCluster = Cluster.open(args.get(0)); + final boolean useSession = args.size() >= 2 && (args.get(1).equals(TOKEN_SESSION) || args.get(1).equals(TOKEN_SESSION_MANAGED)); + if (useSession) { + final String sessionName = args.size() == 3 ? args.get(2) : UUID.randomUUID().toString(); + session = Optional.of(sessionName); + + final boolean managed = args.get(1).equals(TOKEN_SESSION_MANAGED); + + this.currentClient = this.currentCluster.connect(sessionName, managed); + } else { + this.currentClient = this.currentCluster.connect(); + } + this.currentClient.init(); + return String.format("Configured %s", this.currentCluster) + getSessionStringSegment(); + } catch (final FileNotFoundException ignored) { + throw new RemoteException("The 'connect' option must be accompanied by a valid configuration file"); + } catch (final Exception ex) { + throw new RemoteException("Error during 'connect' - " + ex.getMessage(), ex); + } + } + + @Override + public Object configure(final List args) throws RemoteException { + final String option = args.size() == 0 ? "" : args.get(0); + if (!POSSIBLE_TOKENS.contains(option)) + throw new RemoteException(String.format("The 'config' option expects one of ['%s'] as an argument", String.join(",", POSSIBLE_TOKENS))); + + final List arguments = args.subList(1, args.size()); + + if (option.equals(TOKEN_TIMEOUT)) { + final String errorMessage = "The timeout option expects a positive integer representing milliseconds or 'none' as an argument"; + if (arguments.size() != 1) throw new RemoteException(errorMessage); + try { + // first check for MAX timeout then NONE and finally parse the config to int. "max" is now "deprecated" + // in the sense that it will no longer be promoted. support for it will be removed at a later date + timeout = arguments.get(0).equals(TOKEN_MAX) ? Integer.MAX_VALUE : + arguments.get(0).equals(TOKEN_NONE) ? NO_TIMEOUT : Integer.parseInt(arguments.get(0)); + if (timeout < NO_TIMEOUT) throw new RemoteException("The value for the timeout cannot be less than " + NO_TIMEOUT); + return timeout == NO_TIMEOUT ? "Remote timeout is disabled" : "Set remote timeout to " + timeout + "ms"; + } catch (Exception ignored) { + throw new RemoteException(errorMessage); + } + } else if (option.equals(TOKEN_ALIAS)) { + if (arguments.size() == 1 && arguments.get(0).equals(TOKEN_RESET)) { + aliases.clear(); + return "Aliases cleared"; + } + + if (arguments.size() == 1 && arguments.get(0).equals(TOKEN_SHOW)) { + return aliases; + } + + if (arguments.size() % 2 != 0) + throw new RemoteException("Arguments to alias must be 'reset' to clear any existing alias settings or key/value alias/binding pairs"); + + final Map aliasMap = ElementHelper.asMap(arguments.toArray()); + aliases.clear(); + aliasMap.forEach((k,v) -> aliases.put(k, v.toString())); + return aliases; + } + + return this.toString(); + } + + @Override + public Object submit(final List args) throws RemoteException { + final String line = getScript(String.join(" ", args), this.shell); + + try { + final List resultSet = send(line); + this.shell.getInterp().getContext().setProperty(RESULT, resultSet); + return resultSet.stream().map(result -> result.getObject()).iterator(); + } catch (SaslException sasl) { + throw new RemoteException("Security error - check username/password and related settings", sasl); + } catch (Exception ex) { + final Optional inner = findResponseException(ex); + if (inner.isPresent()) { + final ResponseException responseException = inner.get(); + if (responseException.getResponseStatusCode() == ResponseStatusCode.SERVER_ERROR_SERIALIZATION) + throw new RemoteException(String.format("Server could not serialize the result requested. Server error - %s. Note that the class must be serializable by the client and server for proper operation.", responseException.getMessage())); + else + throw new RemoteException(responseException.getMessage()); + } else if (ex.getCause() != null) { + final Throwable rootCause = ExceptionUtils.getRootCause(ex); + if (rootCause instanceof TimeoutException) + throw new RemoteException("Host did not respond in a timely fashion - check the server status and submit again."); + else + throw new RemoteException(rootCause.getMessage()); + } else + throw new RemoteException(ex.getMessage()); + } + } + + @Override + public void close() throws IOException { + if (this.currentClient != null) this.currentClient.close(); + if (this.currentCluster != null) this.currentCluster.close(); + } + + public int getTimeout() { + return timeout; + } + + private List send(final String gremlin) throws SaslException { + try { + final ResultSet rs = this.currentClient.submitAsync(gremlin, aliases, Collections.emptyMap()).get(); + return timeout > NO_TIMEOUT ? rs.all().get(timeout, TimeUnit.MILLISECONDS) : rs.all().get(); + } catch(TimeoutException ignored) { + throw new IllegalStateException("Request timed out while processing - increase the timeout with the :remote command"); + } catch (Exception e) { + // handle security error as-is and unwrapped + final Optional throwable = Stream.of(ExceptionUtils.getThrowables(e)).filter(t -> t instanceof SaslException).findFirst(); + if (throwable.isPresent()) + throw (SaslException) throwable.get(); + + throw new IllegalStateException(e.getMessage(), e); + } + } + + @Override + public boolean allowRemoteConsole() { + return true; + } + + @Override + public String toString() { + return "Gremlin Server - [" + this.currentCluster + "]" + getSessionStringSegment(); + } + + private Optional findResponseException(final Throwable ex) { + if (ex instanceof ResponseException) + return Optional.of((ResponseException) ex); + + if (null == ex.getCause()) + return Optional.empty(); + + return findResponseException(ex.getCause()); + } + + private String getSessionStringSegment() { + return session.isPresent() ? String.format("-[%s]", session.get()) : ""; + } + + /** + * Retrieve a script as defined in the shell context. This allows for multi-line scripts to be submitted. + */ + public static String getScript(final String submittedScript, final Groovysh shell) { + return submittedScript.startsWith("@") ? shell.getInterp().getContext().getProperty(submittedScript.substring(1)).toString() : submittedScript; + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiGremlinPlugin.java new file mode 100644 index 0000000..7698112 --- /dev/null +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/GephiGremlinPlugin.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.console.jsr223; + +import org.apache.tinkerpop.gremlin.jsr223.AbstractGremlinPlugin; +import org.apache.tinkerpop.gremlin.jsr223.console.ConsoleCustomizer; +import org.codehaus.groovy.tools.shell.Groovysh; +import org.codehaus.groovy.tools.shell.IO; + +import java.util.Map; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class GephiGremlinPlugin extends AbstractGremlinPlugin { + private static final String NAME = "tinkerpop.gephi"; + + public GephiGremlinPlugin() { + super(NAME, new GephiConsoleCustomizer()); + } + + private static class GephiConsoleCustomizer implements ConsoleCustomizer { + @Override + public org.apache.tinkerpop.gremlin.jsr223.console.RemoteAcceptor getRemoteAcceptor(final Map environment) { + return new GephiRemoteAcceptor((Groovysh) environment.get(ConsoleCustomizer.ENV_CONSOLE_SHELL), + (IO) environment.get(ConsoleCustomizer.ENV_CONSOLE_IO)); + } + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPlugin.java new file mode 100644 index 0000000..57bacda --- /dev/null +++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPlugin.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tinkerpop.gremlin.console.jsr223; + +import groovyx.gbench.Benchmark; +import groovyx.gbench.BenchmarkStaticExtension; +import groovyx.gprof.ProfileStaticExtension; +import groovyx.gprof.Profiler; +import org.apache.tinkerpop.gremlin.jsr223.AbstractGremlinPlugin; +import org.apache.tinkerpop.gremlin.jsr223.DefaultImportCustomizer; +import org.apache.tinkerpop.gremlin.jsr223.DefaultScriptCustomizer; +import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer; +import org.apache.tinkerpop.gremlin.jsr223.ScriptCustomizer; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class UtilitiesGremlinPlugin extends AbstractGremlinPlugin { + + private static final String NAME = "tinkerpop.utilities"; + + private static final ImportCustomizer imports; + + private static final ScriptCustomizer scripts; + + static { + try { + imports = DefaultImportCustomizer.build() + .addClassImports(groovyx.gbench.Benchmark.class, + groovyx.gbench.BenchmarkBuilder.class, + groovyx.gbench.BenchmarkConstants.class, + groovyx.gbench.BenchmarkContext.class, + groovyx.gbench.Benchmarker.class, + groovyx.gbench.BenchmarkList.class, + groovyx.gbench.BenchmarkLogger.class, + groovyx.gbench.BenchmarkMath.class, + groovyx.gbench.BenchmarkMeasure.class, + groovyx.gbench.BenchmarkStaticExtension.class, + groovyx.gbench.BenchmarkSystem.class, + groovyx.gbench.BenchmarkTime.class, + groovyx.gbench.BenchmarkWarmUp.class, + groovyx.gprof.Profiler.class, + groovyx.gprof.ProfileStaticExtension.class, + groovyx.gprof.CallFilter.class, + groovyx.gprof.CallInfo.class, + groovyx.gprof.CallInterceptor.class, + groovyx.gprof.CallMatcher.class, + groovyx.gprof.CallTree.class, + groovyx.gprof.MethodCallFilter.class, + groovyx.gprof.MethodCallInfo.class, + groovyx.gprof.MethodInfo.class, + groovyx.gprof.ProfileMetaClass.class, + groovyx.gprof.ProxyReport.class, + groovyx.gprof.Report.class, + groovyx.gprof.ReportElement.class, + groovyx.gprof.ReportNormalizer.class, + groovyx.gprof.ReportPrinter.class, + groovyx.gprof.ThreadInfo.class, + groovyx.gprof.ThreadRunFilter.class, + groovyx.gprof.Utils.class) + .addMethodImports( + ProfileStaticExtension.class.getMethod("profile", Object.class, Callable.class), + ProfileStaticExtension.class.getMethod("profile", Object.class, Map.class, Callable.class)).create(); + + final BufferedReader reader = new BufferedReader(new InputStreamReader(UtilitiesGremlinPlugin.class.getResourceAsStream("UtilitiesGremlinPluginScript.groovy"))); + final List lines = new ArrayList<>(); + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + reader.close(); + + scripts = new DefaultScriptCustomizer(Collections.singletonList(lines)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public UtilitiesGremlinPlugin() { + super(NAME, imports, scripts); + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin b/gremlin-console/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin new file mode 100644 index 0000000..631c889 --- /dev/null +++ b/gremlin-console/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinPlugin @@ -0,0 +1,3 @@ +org.apache.tinkerpop.gremlin.console.jsr223.DriverGremlinPlugin +org.apache.tinkerpop.gremlin.console.jsr223.GephiGremlinPlugin +org.apache.tinkerpop.gremlin.console.jsr223.UtilitiesGremlinPlugin \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginScript.groovy ---------------------------------------------------------------------- diff --git a/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginScript.groovy b/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginScript.groovy new file mode 100644 index 0000000..5f5e3c6 --- /dev/null +++ b/gremlin-console/src/main/resources/org/apache/tinkerpop/gremlin/console/jsr223/UtilitiesGremlinPluginScript.groovy @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * @author Daniel Kuppitz (http://thinkaurelius.com) + * @author Marko A. Rodriguez (http://markorodriguez.com) + * @author Stephen Mallette (http://stephen.genoprime.com) + */ + +describeGraph = { Class c -> + def lf = System.getProperty("line.separator") + def optIns = c.getAnnotationsByType(org.apache.tinkerpop.gremlin.structure.Graph.OptIn) + def optOuts = c.getAnnotationsByType(org.apache.tinkerpop.gremlin.structure.Graph.OptOut) + + def optInCount = optIns != null ? optIns.size() : 0 + def optOutCount = optOuts != null ? optOuts.size() : 0 + def suitesSupported = optIns != null && optIns.size() > 0 ? optIns.collect { "> " + it.value() }.join(lf) : "> none" + def testsOptedOut = optOuts != null && optOuts.size() > 0 ? optOuts.collect { "> " + it.test() + "#" + it.method() + "${lf}\t\"" + it.reason() + "\"" }.join(lf) : "> none"; + + // not the use of {lf} here rather than triple quoted string is that groovy 2.4.0 seems to have trouble + // parsing that into groovysh - note the bug report here: https://jira.codehaus.org/browse/GROOVY-7290 + return "${lf}" + +"IMPLEMENTATION - ${c.getCanonicalName()} ${lf}" + +"TINKERPOP TEST SUITE ${lf}" + +"- Compliant with ($optInCount of 10 suites) ${lf}" + +"$suitesSupported ${lf}" + +"- Opts out of $optOutCount individual tests ${lf}" + +"$testsOptedOut ${lf}" + +"- NOTE - ${lf}" + +"The describeGraph() function shows information about a Graph implementation. ${lf}" + +"It uses information found in Java Annotations on the implementation itself to ${lf}" + +"determine this output and does not assess the actual code of the test cases of ${lf}" + +"the implementation itself. Compliant implementations will faithfully and ${lf}" + +"honestly supply these Annotations to provide the most accurate depiction of ${lf}" + +"their support." +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a91fb80e/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GremlinPluginAdapterTest.java ---------------------------------------------------------------------- diff --git a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GremlinPluginAdapterTest.java b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GremlinPluginAdapterTest.java index 77422da..dd582b1 100644 --- a/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GremlinPluginAdapterTest.java +++ b/gremlin-console/src/test/java/org/apache/tinkerpop/gremlin/console/groovy/plugin/GremlinPluginAdapterTest.java @@ -19,10 +19,7 @@ package org.apache.tinkerpop.gremlin.console.groovy.plugin; import org.apache.tinkerpop.gremlin.console.plugin.PluggedIn; -import org.apache.tinkerpop.gremlin.jsr223.BindingsCustomizer; import org.apache.tinkerpop.gremlin.jsr223.ImportGremlinPlugin; -import org.apache.tinkerpop.gremlin.jsr223.ScriptCustomizer; -import org.apache.tinkerpop.gremlin.jsr223.ScriptFileGremlinPlugin; import org.junit.Test; import java.time.DayOfWeek; @@ -44,7 +41,7 @@ public class GremlinPluginAdapterTest { .classImports(java.awt.Color.class, java.sql.CallableStatement.class) .enumImports(DayOfWeek.SATURDAY, DayOfWeek.SUNDAY) .methodImports(DayOfWeek.class.getMethod("from", TemporalAccessor.class), DayOfWeek.class.getMethod("values")).create(); - final PluggedIn.GremlinPluginAdapter adapter = new PluggedIn.GremlinPluginAdapter(plugin); + final PluggedIn.GremlinPluginAdapter adapter = new PluggedIn.GremlinPluginAdapter(plugin, null, null); assertEquals(plugin.getName(), adapter.getName());