blob: 954118b01eb162b559c140bb78918b8ed38d8641 [file] [log] [blame]
/*
* 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.structure;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.tinkerpop.gremlin.GraphProvider;
import org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
import org.apache.tinkerpop.gremlin.process.remote.RemoteConnection;
import org.apache.tinkerpop.gremlin.process.traversal.AnonymousTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
import org.apache.tinkerpop.gremlin.structure.util.GraphFactory;
import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.Iterator;
/**
* {@code RemoteGraph} is only required for integrating with the test suite as there must be a {@link Graph} instance
* for the test suite to bind to. Test suites that use this must ensure that the {@link TraversalSource} be
* generated from their {@link GraphProvider} in via {@link AnonymousTraversalSource#withRemote(RemoteConnection)} or
* similar overload. See {@code RemoteGraphProvider} in the gremlin-server module for an example.
*
* @author Stephen Mallette (http://stephen.genoprime.com)
*/
@Graph.OptIn(Graph.OptIn.SUITE_PROCESS_STANDARD)
@Graph.OptIn(Graph.OptIn.SUITE_PROCESS_COMPUTER)
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ShortestPathTest",
method = "*",
reason = "https://issues.apache.org/jira/browse/TINKERPOP-1976")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ConnectedComponentTest",
method = "*",
reason = "https://issues.apache.org/jira/browse/TINKERPOP-1976")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.CoreTraversalTest",
method = "*",
reason = "The test suite does not support profiling or lambdas and for groovy tests: 'Could not locate method: GraphTraversalSource.withStrategies([{traversalCategory=interface org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy$DecorationStrategy}])'")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ProgramTest",
method = "*",
reason = "RemoteGraph retrieves detached vertices that can't be attached to a remote OLAP graph")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategyProcessTest",
method = "*",
reason = "RemoteGraph does not support ElementIdStrategy at this time - it requires a lambda in construction which is not serializable")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.EventStrategyProcessTest",
method = "*",
reason = "RemoteGraph does not support EventStrategy at this time - some of its members are not serializable")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategyProcessTest",
method = "*",
reason = "RemoteGraph does not support PartitionStrategy at this time")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.ranking.pagerank.PageRankVertexProgramTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.search.path.ShortestPathVertexProgramTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.bulkloading.BulkLoaderVertexProgramTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.bulkdumping.BulkDumperVertexProgramTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.clone.CloneVertexProgramTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.computer.GraphComputerTest",
method = "*",
reason = "RemoteGraph does not support direct Graph.compute() access")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionTest",
method = "*",
reason = "The interruption model in the test can't guarantee interruption at the right time with RemoteGraph.")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.TraversalInterruptionComputerTest",
method = "*",
reason = "The interruption model in the test can't guarantee interruption at the right time with RemoteGraph.")
public class RemoteGraph implements Graph {
private final RemoteConnection connection;
private final Configuration conf;
private RemoteGraph(final RemoteConnection connection, final Configuration conf) {
this.connection = connection;
this.conf = conf;
}
/**
* Creates a new {@link RemoteGraph} instance using the specified configuration, which allows {@link RemoteGraph}
* to be compliant with {@link GraphFactory}. Expects key for {@link RemoteConnection#GREMLIN_REMOTE_CONNECTION_CLASS}
* as well as any configuration required by the underlying {@link RemoteConnection} which will be instantiated.
* Note that the {@code Configuration} object is passed down without change to the creation of the
* {@link RemoteConnection} instance.
*/
public static RemoteGraph open(final Configuration conf) {
if (!conf.containsKey(RemoteConnection.GREMLIN_REMOTE_CONNECTION_CLASS))
throw new IllegalArgumentException("Configuration must contain the '" + RemoteConnection.GREMLIN_REMOTE_CONNECTION_CLASS + "' key");
final RemoteConnection remoteConnection;
try {
final Class<? extends RemoteConnection> clazz = Class.forName(conf.getString(RemoteConnection.GREMLIN_REMOTE_CONNECTION_CLASS)).asSubclass(RemoteConnection.class);
final Constructor<? extends RemoteConnection> ctor = clazz.getConstructor(Configuration.class);
remoteConnection = ctor.newInstance(conf);
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return new RemoteGraph(remoteConnection, conf);
}
public static RemoteGraph open(final String configFile) throws Exception {
return open(new PropertiesConfiguration(configFile));
}
/**
* Creates a new {@link RemoteGraph} instance. {@link RemoteGraph} will attempt to call the
* {@link RemoteConnection#close()} method when the {@link #close()} method is called on this class.
*
* @param connection the {@link RemoteConnection} instance to use
* {@link RemoteConnection}
*/
public static RemoteGraph open(final RemoteConnection connection, final Configuration conf) {
return new RemoteGraph(connection, conf);
}
public RemoteConnection getConnection() {
return connection;
}
/**
* Closes the underlying {@link RemoteConnection}.
*/
@Override
public void close() throws Exception {
connection.close();
}
@Override
public Vertex addVertex(final Object... keyValues) {
throw new UnsupportedOperationException(String.format("RemoteGraph is a proxy to %s - this method is not supported", connection));
}
@Override
public <C extends GraphComputer> C compute(final Class<C> graphComputerClass) throws IllegalArgumentException {
throw new UnsupportedOperationException(String.format("RemoteGraph is a proxy to %s - this method is not supported", connection));
}
@Override
public GraphComputer compute() throws IllegalArgumentException {
throw new UnsupportedOperationException(String.format("RemoteGraph is a proxy to %s - this method is not supported", connection));
}
/**
* This method returns an empty {@link Iterator} - it is not meant to be called directly.
*/
@Override
public Iterator<Vertex> vertices(final Object... vertexIds) {
return Collections.emptyIterator();
}
/**
* This method returns an empty {@link Iterator} - it is not meant to be called directly.
*/
@Override
public Iterator<Edge> edges(final Object... edgeIds) {
return Collections.emptyIterator();
}
@Override
public Transaction tx() {
throw new UnsupportedOperationException(String.format("RemoteGraph is a proxy to %s - this method is not supported", connection));
}
@Override
public Variables variables() {
throw new UnsupportedOperationException(String.format("RemoteGraph is a proxy to %s - this method is not supported", connection));
}
@Override
public Configuration configuration() {
return conf;
}
@Override
public Features features() {
return RemoteFeatures.INSTANCE;
}
@Override
public String toString() {
return StringFactory.graphString(this, connection.toString());
}
public static class RemoteFeatures implements Features {
static RemoteFeatures INSTANCE = new RemoteFeatures();
private RemoteFeatures() {
}
@Override
public GraphFeatures graph() {
return RemoteGraphFeatures.INSTANCE;
}
}
public static class RemoteGraphFeatures implements Features.GraphFeatures {
static RemoteGraphFeatures INSTANCE = new RemoteGraphFeatures();
private RemoteGraphFeatures() {
}
@Override
public boolean supportsTransactions() {
return false;
}
@Override
public boolean supportsThreadedTransactions() {
return false;
}
}
}