org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTransaction Maven / Gradle / Ivy
The newest version!
/*
* 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.tinkerpop.gremlin.process.remote.RemoteConnection;
import org.apache.tinkerpop.gremlin.process.remote.RemoteConnectionException;
import org.apache.tinkerpop.gremlin.process.remote.traversal.RemoteTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
import org.apache.tinkerpop.gremlin.process.traversal.GraphOp;
import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource;
import org.apache.tinkerpop.gremlin.structure.Transaction;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_COMMIT;
import static org.apache.tinkerpop.gremlin.process.traversal.GraphOp.TX_ROLLBACK;
/**
* A remote {@link Transaction} implementation that is implemented with the Java driver. It is also a proxy for a
* {@link RemoteConnection} that is bound to a session.
*
* For users, starting a transaction with {@link #begin()} will produce a {@link TraversalSource} that can be used
* across multiple threads sending the bytecode based requests to a remote session. It is worth noting that the session
* will process these requests in a serial fashion and not in parallel. Calling {@link #commit()} or
* {@link #rollback()} will also close the session and no additional traversal can be executed on the
* {@link TraversalSource}. A fresh call to {@link #begin()} will be required to open a fresh session to work with.
* The default behavior of {@link #close()} is to commit the transaction.
*/
public class DriverRemoteTransaction implements Transaction, RemoteConnection {
private final DriverRemoteConnection sessionBasedConnection;
protected Consumer closeConsumer = CLOSE_BEHAVIOR.COMMIT;
public DriverRemoteTransaction(final DriverRemoteConnection sessionBasedConnection) {
this.sessionBasedConnection = sessionBasedConnection;
}
@Override
public T begin(final Class traversalSourceClass) {
if (!isOpen())
throw new IllegalStateException("Transaction cannot begin as the session is already closed - create a new Transaction");
try {
return traversalSourceClass.getConstructor(RemoteConnection.class).newInstance(this);
} catch (final Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* By virtue of creating a {@code DriverRemoteTransaction}, the transaction is considered open. There is no need
* to call this method. Calling it when the transaction is closed will result in exception.
*/
@Override
public void open() {
// no need to issue a command to open the transaction, the server is already in such a state if the
if (!isOpen())
throw new IllegalStateException("Transaction cannot be opened as the session is already closed - create a new Transaction");
}
@Override
public void commit() {
closeRemoteTransaction(TX_COMMIT, "Transaction commit for %s failed");
}
@Override
public void rollback() {
closeRemoteTransaction(TX_ROLLBACK, "Transaction rollback for %s failed");
}
private void closeRemoteTransaction(final GraphOp closeTxWith, final String failureMsg) {
try {
// kinda weird but we hasNext() the graph command here to ensure that it runs to completion or
// else you don't guarantee that we have the returned NO_CONTENT message in hand before proceeding
// which could mean the transaction is still in the process of committing. not sure why iterate()
// doesn't quite work in this context.
this.sessionBasedConnection.submitAsync(closeTxWith.getBytecode()).join().hasNext();
this.sessionBasedConnection.close();
} catch (Exception ex) {
throw new RuntimeException(String.format(failureMsg, sessionBasedConnection.getSessionId()), ex);
}
}
@Override
public boolean isOpen() {
// for tx purposes closing is a good enough check
return !sessionBasedConnection.client.isClosing();
}
/**
* The default close behavior for this {@link Transaction} implementation is to {@link #commit()}.
*/
@Override
public void close() {
this.closeConsumer.accept(this);
}
/**
* This {@link Transaction} implementation is not auto-managed and therefore this method is not supported.
*/
@Override
public void readWrite() {
throw new UnsupportedOperationException("Remote transaction behaviors are not auto-managed - they are always manually controlled");
}
/**
* This {@link Transaction} implementation is not auto-managed and therefore this method is not supported.
*/
@Override
public Transaction onReadWrite(final Consumer consumer) {
throw new UnsupportedOperationException("Remote transaction behaviors are not configurable - they are always manually controlled");
}
@Override
public Transaction onClose(final Consumer consumer) {
this.closeConsumer = consumer;
return this;
}
/**
* There is no support for remote transaction listeners.
*/
@Override
public void addTransactionListener(final Consumer listener) {
throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
}
/**
* There is no support for remote transaction listeners.
*/
@Override
public void removeTransactionListener(final Consumer listener) {
throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
}
/**
* There is no support for remote transaction listeners.
*/
@Override
public void clearTransactionListeners() {
throw new UnsupportedOperationException("Remote transactions cannot have listeners attached");
}
/**
* It is not possible to have child transactions, therefore this method always returns {@link Transaction#NO_OP}.
*/
@Override
public Transaction tx() {
return Transaction.NO_OP;
}
@Override
public CompletableFuture> submitAsync(final Bytecode bytecode) throws RemoteConnectionException {
return sessionBasedConnection.submitAsync(bytecode);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy