/* * 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.driver.remote; import org.apache.commons.configuration.Configuration; import org.apache.tinkerpop.gremlin.AbstractGraphProvider; import org.apache.tinkerpop.gremlin.LoadGraphWith; import org.apache.tinkerpop.gremlin.driver.Client; import org.apache.tinkerpop.gremlin.driver.Cluster; import org.apache.tinkerpop.gremlin.driver.ser.Serializers; import org.apache.tinkerpop.gremlin.process.remote.RemoteGraph; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.server.GremlinServer; import org.apache.tinkerpop.gremlin.server.ServerTestHelper; import org.apache.tinkerpop.gremlin.server.Settings; import org.apache.tinkerpop.gremlin.server.TestClientFactory; import org.apache.tinkerpop.gremlin.structure.Graph; import java.io.InputStream; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** * @author Stephen Mallette (http://stephen.genoprime.com) */ public class RemoteGraphProvider extends AbstractGraphProvider implements AutoCloseable { private static final Set<Class> IMPLEMENTATION = new HashSet<Class>() {{ add(RemoteGraph.class); }}; private static GremlinServer server; private final Map<String, RemoteGraph> remoteCache = new HashMap<>(); private final Cluster cluster = TestClientFactory.open(); //private final Cluster cluster = Cluster.build().maxContentLength(1024000).serializer(Serializers.GRAPHSON_V2D0).create(); private final Client client = cluster.connect(); public RemoteGraphProvider() { try { startServer(); } catch (Exception ex) { throw new RuntimeException(ex); } } @Override public void close() throws Exception { try { stopServer(); } catch (Exception ex) { throw new RuntimeException(ex); } } @Override public Graph openTestGraph(final Configuration config) { final String serverGraphName = config.getString(DriverRemoteConnection.GREMLIN_REMOTE_DRIVER_SOURCENAME); return remoteCache.computeIfAbsent(serverGraphName, k -> RemoteGraph.open(new DriverRemoteConnection(cluster, config))); } @Override public Map<String, Object> getBaseConfiguration(final String graphName, Class<?> test, final String testMethodName, final LoadGraphWith.GraphData loadGraphWith) { final String serverGraphName = getServerGraphName(loadGraphWith); final Supplier<Graph> graphGetter = () -> server.getServerGremlinExecutor().getGraphManager().getGraph(serverGraphName); return new HashMap<String, Object>() {{ put(Graph.GRAPH, RemoteGraph.class.getName()); put(RemoteGraph.GREMLIN_REMOTE_GRAPH_REMOTE_CONNECTION_CLASS, DriverRemoteConnection.class.getName()); put(DriverRemoteConnection.GREMLIN_REMOTE_DRIVER_SOURCENAME, "g" + serverGraphName); put("clusterConfiguration.port", TestClientFactory.PORT); put("clusterConfiguration.hosts", "localhost"); put("hidden.for.testing.only", graphGetter); }}; } @Override public void clear(final Graph graph, final Configuration configuration) throws Exception { // doesn't bother to clear grateful because i don't believe that ever gets mutated - read-only client.submit("classic.clear();modern.clear();crew.clear();graph.clear();" + "TinkerFactory.generateClassic(classic);" + "TinkerFactory.generateModern(modern);" + "TinkerFactory.generateTheCrew(crew);null").all().get(); } @Override public void loadGraphData(final Graph graph, final LoadGraphWith loadGraphWith, final Class testClass, final String testName) { // server already loads with the all the graph instances for LoadGraphWith } @Override public Set<Class> getImplementations() { return IMPLEMENTATION; } @Override public GraphTraversalSource traversal(final Graph graph) { // ensure that traversal is created using withRemote() rather than just using RemoteGraph. withRemote() is // the appropriate way for users to create a remote traversal. RemoteGraph has been deprecated for users // concerns and will be likely relegated to the test module so that OptOut can continue to work and we can // full execute the process tests. we should be able to clean this up considerably when RemoteGraph can be // moved with breaking change. return super.traversal(graph).withRemote(((RemoteGraph) graph).getConnection()); } public static void startServer() throws Exception { final InputStream stream = RemoteGraphProvider.class.getResourceAsStream("gremlin-server-integration.yaml"); final Settings settings = Settings.read(stream); ServerTestHelper.rewritePathsInGremlinServerSettings(settings); settings.maxContentLength = 1024000; settings.maxChunkSize =1024000; server = new GremlinServer(settings); server.start().get(100, TimeUnit.SECONDS); } public static void stopServer() throws Exception { server.stop().get(100, TimeUnit.SECONDS); server = null; } private static String getServerGraphName(final LoadGraphWith.GraphData loadGraphWith) { final String serverGraphName; if (null == loadGraphWith) return "graph"; switch (loadGraphWith) { case CLASSIC: serverGraphName = "classic"; break; case MODERN: serverGraphName = "modern"; break; case GRATEFUL: serverGraphName = "grateful"; break; case CREW: serverGraphName = "crew"; break; default: serverGraphName = "graph"; break; } return serverGraphName; } }