// Copyright 2017 JanusGraph Authors // // 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. package org.janusgraph.graphdb.tinkerpop; import com.google.common.base.Preconditions; import org.janusgraph.core.*; import org.janusgraph.core.schema.EdgeLabelMaker; import org.janusgraph.core.schema.PropertyKeyMaker; import org.janusgraph.core.schema.VertexLabelMaker; import org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration; import org.janusgraph.graphdb.database.StandardJanusGraph; import org.janusgraph.graphdb.olap.computer.FulgoraGraphComputer; import org.apache.commons.configuration.Configuration; import org.apache.tinkerpop.gremlin.process.computer.GraphComputer; import org.apache.tinkerpop.gremlin.structure.Edge; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Transaction; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.structure.io.Io; import org.apache.tinkerpop.gremlin.structure.util.AbstractThreadLocalTransaction; import org.apache.tinkerpop.gremlin.structure.util.StringFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Iterator; import java.util.function.Consumer; /** * Blueprints specific implementation for {@link JanusGraph}. * Handles thread-bound transactions. * * @author Matthias Broecheler (me@matthiasb.com) */ public abstract class JanusGraphBlueprintsGraph implements JanusGraph { private static final Logger log = LoggerFactory.getLogger(JanusGraphBlueprintsGraph.class); // ########## TRANSACTION HANDLING ########################### final GraphTransaction tinkerpopTxContainer = new GraphTransaction(); private ThreadLocal<JanusGraphBlueprintsTransaction> txs = new ThreadLocal<JanusGraphBlueprintsTransaction>() { protected JanusGraphBlueprintsTransaction initialValue() { return null; } }; public abstract JanusGraphTransaction newThreadBoundTransaction(); private JanusGraphBlueprintsTransaction getAutoStartTx() { if (txs == null) throw new IllegalStateException("Graph has been closed"); tinkerpopTxContainer.readWrite(); JanusGraphBlueprintsTransaction tx = txs.get(); Preconditions.checkState(tx!=null,"Invalid read-write behavior configured: " + "Should either open transaction or throw exception."); return tx; } private JanusGraphBlueprintsTransaction startNewTx() { JanusGraphBlueprintsTransaction tx = txs.get(); if (tx!=null && tx.isOpen()) throw Transaction.Exceptions.transactionAlreadyOpen(); tx = (JanusGraphBlueprintsTransaction) newThreadBoundTransaction(); txs.set(tx); log.debug("Created new thread-bound transaction {}", tx); return tx; } public JanusGraphTransaction getCurrentThreadTx() { return getAutoStartTx(); } @Override public synchronized void close() { txs = null; } @Override public Transaction tx() { return tinkerpopTxContainer; } @Override public String toString() { GraphDatabaseConfiguration config = ((StandardJanusGraph) this).getConfiguration(); return StringFactory.graphString(this,config.getBackendDescription()); } @Override public Variables variables() { return new JanusGraphVariables(((StandardJanusGraph)this).getBackend().getUserConfiguration()); } @Override public Configuration configuration() { GraphDatabaseConfiguration config = ((StandardJanusGraph) this).getConfiguration(); return config.getConfigurationAtOpen(); } @Override public <I extends Io> I io(final Io.Builder<I> builder) { return (I) builder.graph(this).onMapper(mapper -> mapper.addRegistry(JanusGraphIoRegistry.getInstance())).create(); } // ########## TRANSACTIONAL FORWARDING ########################### @Override public JanusGraphVertex addVertex(Object... keyValues) { return getAutoStartTx().addVertex(keyValues); } @Override public Iterator<Vertex> vertices(Object... vertexIds) { return getAutoStartTx().vertices(vertexIds); } @Override public Iterator<Edge> edges(Object... edgeIds) { return getAutoStartTx().edges(edgeIds); } @Override public <C extends GraphComputer> C compute(Class<C> graphComputerClass) throws IllegalArgumentException { if (!graphComputerClass.equals(FulgoraGraphComputer.class)) { throw Graph.Exceptions.graphDoesNotSupportProvidedGraphComputer(graphComputerClass); } else { return (C)compute(); } } @Override public FulgoraGraphComputer compute() throws IllegalArgumentException { StandardJanusGraph graph = (StandardJanusGraph)this; return new FulgoraGraphComputer(graph,graph.getConfiguration().getConfiguration()); } @Override public JanusGraphVertex addVertex(String vertexLabel) { return getAutoStartTx().addVertex(vertexLabel); } @Override public JanusGraphQuery<? extends JanusGraphQuery> query() { return getAutoStartTx().query(); } @Override public JanusGraphIndexQuery indexQuery(String indexName, String query) { return getAutoStartTx().indexQuery(indexName,query); } @Override @Deprecated public JanusGraphMultiVertexQuery multiQuery(JanusGraphVertex... vertices) { return getAutoStartTx().multiQuery(vertices); } @Override @Deprecated public JanusGraphMultiVertexQuery multiQuery(Collection<JanusGraphVertex> vertices) { return getAutoStartTx().multiQuery(vertices); } //Schema @Override public PropertyKeyMaker makePropertyKey(String name) { return getAutoStartTx().makePropertyKey(name); } @Override public EdgeLabelMaker makeEdgeLabel(String name) { return getAutoStartTx().makeEdgeLabel(name); } @Override public VertexLabelMaker makeVertexLabel(String name) { return getAutoStartTx().makeVertexLabel(name); } @Override public boolean containsPropertyKey(String name) { return getAutoStartTx().containsPropertyKey(name); } @Override public PropertyKey getOrCreatePropertyKey(String name) { return getAutoStartTx().getOrCreatePropertyKey(name); } @Override public PropertyKey getPropertyKey(String name) { return getAutoStartTx().getPropertyKey(name); } @Override public boolean containsEdgeLabel(String name) { return getAutoStartTx().containsEdgeLabel(name); } @Override public EdgeLabel getOrCreateEdgeLabel(String name) { return getAutoStartTx().getOrCreateEdgeLabel(name); } @Override public EdgeLabel getEdgeLabel(String name) { return getAutoStartTx().getEdgeLabel(name); } @Override public boolean containsRelationType(String name) { return getAutoStartTx().containsRelationType(name); } @Override public RelationType getRelationType(String name) { return getAutoStartTx().getRelationType(name); } @Override public boolean containsVertexLabel(String name) { return getAutoStartTx().containsVertexLabel(name); } @Override public VertexLabel getVertexLabel(String name) { return getAutoStartTx().getVertexLabel(name); } @Override public VertexLabel getOrCreateVertexLabel(String name) { return getAutoStartTx().getOrCreateVertexLabel(name); } class GraphTransaction extends AbstractThreadLocalTransaction { public GraphTransaction() { super(JanusGraphBlueprintsGraph.this); } @Override public void doOpen() { startNewTx(); } @Override public void doCommit() { getAutoStartTx().commit(); } @Override public void doRollback() { getAutoStartTx().rollback(); } @Override public JanusGraphTransaction createThreadedTx() { return newTransaction(); } @Override public boolean isOpen() { if (null == txs) { // Graph has been closed return false; } JanusGraphBlueprintsTransaction tx = txs.get(); return tx!=null && tx.isOpen(); } @Override public void close() { close(this); } void close(Transaction tx) { closeConsumerInternal.get().accept(tx); Preconditions.checkState(!tx.isOpen(),"Invalid close behavior configured: Should close transaction. [%s]", closeConsumerInternal); } @Override public Transaction onReadWrite(Consumer<Transaction> transactionConsumer) { Preconditions.checkArgument(transactionConsumer instanceof READ_WRITE_BEHAVIOR, "Only READ_WRITE_BEHAVIOR instances are accepted argument, got: %s", transactionConsumer); return super.onReadWrite(transactionConsumer); } @Override public Transaction onClose(Consumer<Transaction> transactionConsumer) { Preconditions.checkArgument(transactionConsumer instanceof CLOSE_BEHAVIOR, "Only CLOSE_BEHAVIOR instances are accepted argument, got: %s", transactionConsumer); return super.onClose(transactionConsumer); } } }