/*
* Copyright (c) 2002-2017 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product may include a number of subcomponents with
* separate copyright notices and license terms. Your use of the source
* code for these subcomponents is subject to the terms and
* conditions of the subcomponent's license, as noted in the LICENSE file.
*/
package org.neo4j.ogm.drivers.bolt.driver;
import java.io.File;
import java.net.URI;
import org.neo4j.driver.v1.*;
import org.neo4j.driver.v1.exceptions.ClientException;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.config.UsernamePasswordCredentials;
import org.neo4j.ogm.driver.AbstractConfigurableDriver;
import org.neo4j.ogm.drivers.bolt.request.BoltRequest;
import org.neo4j.ogm.drivers.bolt.transaction.BoltTransaction;
import org.neo4j.ogm.exception.ConnectionException;
import org.neo4j.ogm.request.Request;
import org.neo4j.ogm.transaction.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Vince Bickers
* @author Luanne Misquitta
* @author Mark Angrish
*/
public class BoltDriver extends AbstractConfigurableDriver {
private final Logger LOGGER = LoggerFactory.getLogger(BoltDriver.class);
private Driver boltDriver;
// required for service loader mechanism
public BoltDriver() {
}
@Override
public void configure(Configuration config) {
close();
super.configure(config);
Config driverConfig = buildDriverConfig(config);
if (config.getCredentials() != null) {
UsernamePasswordCredentials credentials = (UsernamePasswordCredentials) config.getCredentials();
AuthToken authToken = AuthTokens.basic(credentials.getUsername(), credentials.getPassword());
boltDriver = GraphDatabase.driver(config.getURI(), authToken, driverConfig);
} else {
boltDriver = GraphDatabase.driver(config.getURI(), driverConfig);
LOGGER.debug("Bolt Driver credentials not supplied");
}
}
@Override
public Transaction newTransaction(Transaction.Type type, String bookmark) {
Session session = newSession(type); //A bolt session can have at most one transaction running at a time
return new BoltTransaction(transactionManager, nativeTransaction(session, bookmark), session, type);
}
@Override
public synchronized void close() {
if (boltDriver != null) {
try {
LOGGER.info("Shutting down Bolt driver {} ", boltDriver);
boltDriver.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public Request request() {
return new BoltRequest(transactionManager);
}
private Session newSession(Transaction.Type type) {
Session boltSession;
try {
boltSession = boltDriver.session(type.equals(Transaction.Type.READ_ONLY) ? AccessMode.READ : AccessMode.WRITE);
} catch (ClientException ce) {
throw new ConnectionException("Error connecting to graph database using Bolt: " + ce.neo4jErrorCode() + ", " + ce.getMessage(), ce);
} catch (Exception e) {
throw new ConnectionException("Error connecting to graph database using Bolt", e);
}
return boltSession;
}
private org.neo4j.driver.v1.Transaction nativeTransaction(Session session, String bookmark) {
org.neo4j.driver.v1.Transaction nativeTransaction;
Transaction tx = transactionManager.getCurrentTransaction();
if (tx != null) {
LOGGER.debug("Using current transaction: {}", tx);
nativeTransaction = ((BoltTransaction) tx).nativeBoltTransaction();
} else {
if (bookmark != null) {
LOGGER.debug("No current transaction, starting a new one with bookmark [{}]", bookmark);
nativeTransaction = session.beginTransaction(bookmark);
} else {
LOGGER.debug("No current transaction, starting a new one");
nativeTransaction = session.beginTransaction();
}
}
LOGGER.debug("Native transaction: {}", nativeTransaction);
return nativeTransaction;
}
private BoltConfig getBoltConfiguration(Configuration configuration) {
BoltConfig boltConfig = new BoltConfig();
if (configuration.getEncryptionLevel() != null) {
try {
boltConfig.encryptionLevel = Config.EncryptionLevel.valueOf(configuration.getEncryptionLevel().toUpperCase());
} catch (IllegalArgumentException iae) {
LOGGER.debug("Invalid configuration for the Bolt Driver Encryption Level: {}", configuration.getEncryptionLevel());
throw iae;
}
}
boltConfig.sessionPoolSize = configuration.getConnectionPoolSize();
if (configuration.getTrustStrategy() != null) {
try {
boltConfig.trustStrategy = Config.TrustStrategy.Strategy.valueOf(configuration.getTrustStrategy());
} catch (IllegalArgumentException iae) {
LOGGER.debug("Invalid configuration for the Bolt Driver Trust Strategy: {}", configuration.getTrustStrategy());
throw iae;
}
}
if (configuration.getTrustCertFile() != null) {
boltConfig.trustCertFile = configuration.getTrustCertFile();
}
return boltConfig;
}
private Config buildDriverConfig(Configuration driverConfig) {
try {
BoltConfig boltConfig = getBoltConfiguration(driverConfig);
Config.ConfigBuilder configBuilder = Config.build();
configBuilder.withMaxSessions(boltConfig.sessionPoolSize);
configBuilder.withEncryptionLevel(boltConfig.encryptionLevel);
if (boltConfig.trustStrategy != null) {
if (boltConfig.trustCertFile == null) {
throw new IllegalArgumentException("Missing configuration value for trust.certificate.file");
}
if (boltConfig.trustStrategy.equals(Config.TrustStrategy.Strategy.TRUST_ON_FIRST_USE)) {
configBuilder.withTrustStrategy(Config.TrustStrategy.trustOnFirstUse(new File(new URI(boltConfig.trustCertFile))));
}
if (boltConfig.trustStrategy.equals(Config.TrustStrategy.Strategy.TRUST_SIGNED_CERTIFICATES)) {
configBuilder.withTrustStrategy(Config.TrustStrategy.trustSignedBy(new File(new URI(boltConfig.trustCertFile))));
}
}
return configBuilder.toConfig();
} catch (Exception e) {
throw new ConnectionException("Unable to build driver configuration", e);
}
}
class BoltConfig {
public static final int DEFAULT_SESSION_POOL_SIZE = 50;
Config.EncryptionLevel encryptionLevel = Config.EncryptionLevel.REQUIRED;
int sessionPoolSize = DEFAULT_SESSION_POOL_SIZE;
Config.TrustStrategy.Strategy trustStrategy;
String trustCertFile;
}
}