org.neo4j.driver.internal.ExplicitTransaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neo4j-java-driver Show documentation
Show all versions of neo4j-java-driver Show documentation
Access to the Neo4j graph database through Java
/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* 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.neo4j.driver.internal;
import java.util.Collections;
import java.util.Map;
import org.neo4j.driver.internal.spi.Collector;
import org.neo4j.driver.internal.spi.Connection;
import org.neo4j.driver.internal.types.InternalTypeSystem;
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.Statement;
import org.neo4j.driver.v1.StatementResult;
import org.neo4j.driver.v1.Transaction;
import org.neo4j.driver.v1.Value;
import org.neo4j.driver.v1.Values;
import org.neo4j.driver.v1.exceptions.ClientException;
import org.neo4j.driver.v1.exceptions.Neo4jException;
import org.neo4j.driver.v1.types.TypeSystem;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonMap;
import static org.neo4j.driver.v1.Values.ofValue;
import static org.neo4j.driver.v1.Values.value;
public class ExplicitTransaction implements Transaction
{
private enum State
{
/** The transaction is running with no explicit success or failure marked */
ACTIVE,
/** Running, user marked for success, meaning it'll value committed */
MARKED_SUCCESS,
/** User marked as failed, meaning it'll be rolled back. */
MARKED_FAILED,
/**
* An error has occurred, transaction can no longer be used and no more messages will be sent for this
* transaction.
*/
FAILED,
/** This transaction has successfully committed */
SUCCEEDED,
/** This transaction has been rolled back */
ROLLED_BACK
}
private final SessionResourcesHandler resourcesHandler;
private final Connection conn;
private String bookmark = null;
private State state = State.ACTIVE;
public ExplicitTransaction( Connection conn, SessionResourcesHandler resourcesHandler )
{
this( conn, resourcesHandler, null );
}
ExplicitTransaction( Connection conn, SessionResourcesHandler resourcesHandler, String bookmark )
{
this.conn = conn;
this.resourcesHandler = resourcesHandler;
runBeginStatement( conn, bookmark );
}
@Override
public void success()
{
if ( state == State.ACTIVE )
{
state = State.MARKED_SUCCESS;
}
}
@Override
public void failure()
{
if ( state == State.ACTIVE || state == State.MARKED_SUCCESS )
{
state = State.MARKED_FAILED;
}
}
@Override
public void close()
{
try
{
if ( conn != null && conn.isOpen() )
{
if ( state == State.MARKED_SUCCESS )
{
try
{
conn.run( "COMMIT", Collections.emptyMap(), Collector.NO_OP );
conn.pullAll( new BookmarkCollector( this ) );
conn.sync();
state = State.SUCCEEDED;
}
catch( Throwable e )
{
// failed to commit
try
{
rollbackTx();
}
catch( Throwable ignored )
{
// best effort.
}
throw e;
}
}
else if ( state == State.MARKED_FAILED || state == State.ACTIVE )
{
rollbackTx();
}
}
}
finally
{
resourcesHandler.onTransactionClosed( this );
}
}
private void rollbackTx()
{
conn.run( "ROLLBACK", Collections.emptyMap(), Collector.NO_OP );
conn.pullAll( new BookmarkCollector( this ) );
conn.sync();
state = State.ROLLED_BACK;
}
@Override
@SuppressWarnings( "unchecked" )
public StatementResult run( String statementText, Value statementParameters )
{
return run( new Statement( statementText, statementParameters ) );
}
@Override
public StatementResult run( String statementText )
{
return run( statementText, Values.EmptyMap );
}
@Override
public StatementResult run( String statementText, Map statementParameters )
{
Value params = statementParameters == null ? Values.EmptyMap : value(statementParameters);
return run( statementText, params );
}
@Override
public StatementResult run( String statementTemplate, Record statementParameters )
{
Value params = statementParameters == null ? Values.EmptyMap : value( statementParameters.asMap() );
return run( statementTemplate, params );
}
@Override
public synchronized StatementResult run( Statement statement )
{
ensureNotFailed();
try
{
InternalStatementResult result =
new InternalStatementResult( conn, SessionResourcesHandler.NO_OP, this, statement );
conn.run( statement.text(),
statement.parameters().asMap( ofValue() ),
result.runResponseCollector() );
conn.pullAll( result.pullAllResponseCollector() );
conn.flush();
return result;
}
catch ( Neo4jException e )
{
// Failed to send messages to the server probably due to IOException in the socket.
// So we should stop sending more messages in this transaction
state = State.FAILED;
throw e;
}
}
@Override
public boolean isOpen()
{
return state == State.ACTIVE;
}
private void ensureNotFailed()
{
if ( state == State.FAILED || state == State.MARKED_FAILED || state == State.ROLLED_BACK )
{
throw new ClientException(
"Cannot run more statements in this transaction, because previous statements in the " +
"transaction has failed and the transaction has been rolled back. Please start a new" +
" transaction to run another statement."
);
}
}
@Override
public TypeSystem typeSystem()
{
return InternalTypeSystem.TYPE_SYSTEM;
}
public synchronized void markToClose()
{
state = State.FAILED;
}
public String bookmark()
{
return bookmark;
}
void setBookmark( String bookmark )
{
this.bookmark = bookmark;
}
private static void runBeginStatement( Connection connection, String bookmark )
{
Map parameters;
if ( bookmark != null )
{
parameters = singletonMap( "bookmark", value( bookmark ) );
}
else
{
parameters = emptyMap();
}
connection.run( "BEGIN", parameters, Collector.NO_OP );
connection.pullAll( Collector.NO_OP );
if ( bookmark != null )
{
connection.sync();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy