All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.driver.Config Maven / Gradle / Ivy

/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.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;

import static java.lang.String.format;
import static org.neo4j.driver.internal.logging.DevNullLogging.DEV_NULL_LOGGING;

import java.io.File;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.neo4j.driver.internal.RevocationStrategy;
import org.neo4j.driver.internal.SecuritySettings;
import org.neo4j.driver.internal.async.pool.PoolSettings;
import org.neo4j.driver.internal.cluster.RoutingSettings;
import org.neo4j.driver.internal.handlers.pulln.FetchSizeUtil;
import org.neo4j.driver.internal.retry.RetrySettings;
import org.neo4j.driver.net.ServerAddressResolver;
import org.neo4j.driver.util.Experimental;
import org.neo4j.driver.util.Immutable;

/**
 * A configuration class to config driver properties.
 * 

* To build a simple config with custom logging implementation: *

 * {@code
 * Config config = Config.builder()
 *                       .withLogging(new MyLogging())
 *                       .build();
 * }
 * 
*

* To build a more complicated config with tuned connection pool options: *

 * {@code
 * Config config = Config.builder()
 *                       .withEncryption()
 *                       .withConnectionTimeout( 10, TimeUnit.SECONDS)
 *                       .withMaxConnectionLifetime(30, TimeUnit.MINUTES)
 *                       .withMaxConnectionPoolSize(10)
 *                       .withConnectionAcquisitionTimeout(20, TimeUnit.SECONDS)
 *                       .build();
 * }
 * 
* * @since 1.0 */ @Immutable public class Config implements Serializable { private static final long serialVersionUID = -4496545746399601108L; private static final Config EMPTY = builder().build(); /** User defined logging */ private final Logging logging; private final boolean logLeakedSessions; private final int maxConnectionPoolSize; private final long idleTimeBeforeConnectionTest; private final long maxConnectionLifetimeMillis; private final long connectionAcquisitionTimeoutMillis; private final SecuritySettings securitySettings; private final int routingFailureLimit; private final long routingRetryDelayMillis; private final long fetchSize; private final long routingTablePurgeDelayMillis; private final int connectionTimeoutMillis; private final RetrySettings retrySettings; private final ServerAddressResolver resolver; private final int eventLoopThreads; private final String userAgent; private final MetricsAdapter metricsAdapter; private Config(ConfigBuilder builder) { this.logging = builder.logging; this.logLeakedSessions = builder.logLeakedSessions; this.idleTimeBeforeConnectionTest = builder.idleTimeBeforeConnectionTest; this.maxConnectionLifetimeMillis = builder.maxConnectionLifetimeMillis; this.maxConnectionPoolSize = builder.maxConnectionPoolSize; this.connectionAcquisitionTimeoutMillis = builder.connectionAcquisitionTimeoutMillis; this.userAgent = builder.userAgent; this.securitySettings = builder.securitySettingsBuilder.build(); this.routingFailureLimit = builder.routingFailureLimit; this.routingRetryDelayMillis = builder.routingRetryDelayMillis; this.connectionTimeoutMillis = builder.connectionTimeoutMillis; this.routingTablePurgeDelayMillis = builder.routingTablePurgeDelayMillis; this.retrySettings = builder.retrySettings; this.resolver = builder.resolver; this.fetchSize = builder.fetchSize; this.eventLoopThreads = builder.eventLoopThreads; this.metricsAdapter = builder.metricsAdapter; } /** * Logging provider * @return the Logging provider to use */ public Logging logging() { return logging; } /** * Check if leaked sessions logging is enabled. * * @return {@code true} if enabled, {@code false} otherwise. */ public boolean logLeakedSessions() { return logLeakedSessions; } /** * Pooled connections that have been idle in the pool for longer than this timeout * will be tested before they are used again, to ensure they are still live. * * @return idle time in milliseconds */ public long idleTimeBeforeConnectionTest() { return idleTimeBeforeConnectionTest; } /** * Pooled connections older than this threshold will be closed and removed from the pool. * * @return maximum lifetime in milliseconds */ public long maxConnectionLifetimeMillis() { return maxConnectionLifetimeMillis; } /** * @return the configured connection timeout value in milliseconds. */ public int connectionTimeoutMillis() { return connectionTimeoutMillis; } public int maxConnectionPoolSize() { return maxConnectionPoolSize; } public long connectionAcquisitionTimeoutMillis() { return connectionAcquisitionTimeoutMillis; } /** * @return indicator for encrypted communication. */ public boolean encrypted() { return securitySettings.encrypted(); } /** * @return the strategy to use to determine the authenticity of an encryption certificate provided by the Neo4j instance we are connecting to. */ public TrustStrategy trustStrategy() { return securitySettings.trustStrategy(); } /** * Server address resolver. * * @return the resolver to use. */ public ServerAddressResolver resolver() { return resolver; } /** * Start building a {@link Config} object using a newly created builder. * * @return a new {@link ConfigBuilder} instance. */ public static ConfigBuilder builder() { return new ConfigBuilder(); } /** * @return A config with all default settings */ public static Config defaultConfig() { return EMPTY; } /** * @return the security setting to use when creating connections. */ SecuritySettings securitySettings() { return securitySettings; } RoutingSettings routingSettings() { return new RoutingSettings(routingFailureLimit, routingRetryDelayMillis, routingTablePurgeDelayMillis); } RetrySettings retrySettings() { return retrySettings; } public long fetchSize() { return fetchSize; } public int eventLoopThreads() { return eventLoopThreads; } /** * @return if the metrics is enabled or not on this driver. */ public boolean isMetricsEnabled() { return this.metricsAdapter != MetricsAdapter.DEV_NULL; } public MetricsAdapter metricsAdapter() { return this.metricsAdapter; } /** * @return the user_agent configured for this driver */ public String userAgent() { return userAgent; } /** * Used to build new config instances */ public static class ConfigBuilder { private Logging logging = DEV_NULL_LOGGING; private boolean logLeakedSessions; private int maxConnectionPoolSize = PoolSettings.DEFAULT_MAX_CONNECTION_POOL_SIZE; private long idleTimeBeforeConnectionTest = PoolSettings.DEFAULT_IDLE_TIME_BEFORE_CONNECTION_TEST; private long maxConnectionLifetimeMillis = PoolSettings.DEFAULT_MAX_CONNECTION_LIFETIME; private long connectionAcquisitionTimeoutMillis = PoolSettings.DEFAULT_CONNECTION_ACQUISITION_TIMEOUT; private String userAgent = format("neo4j-java/%s", driverVersion()); private final SecuritySettings.SecuritySettingsBuilder securitySettingsBuilder = new SecuritySettings.SecuritySettingsBuilder(); private int routingFailureLimit = RoutingSettings.DEFAULT.maxRoutingFailures(); private long routingRetryDelayMillis = RoutingSettings.DEFAULT.retryTimeoutDelay(); private long routingTablePurgeDelayMillis = RoutingSettings.DEFAULT.routingTablePurgeDelayMs(); private int connectionTimeoutMillis = (int) TimeUnit.SECONDS.toMillis(30); private RetrySettings retrySettings = RetrySettings.DEFAULT; private ServerAddressResolver resolver; private MetricsAdapter metricsAdapter = MetricsAdapter.DEV_NULL; private long fetchSize = FetchSizeUtil.DEFAULT_FETCH_SIZE; private int eventLoopThreads = 0; private ConfigBuilder() {} /** * Provide a logging implementation for the driver to use. Java logging framework {@link java.util.logging} with {@link Level#INFO} is used by default. * Callers are expected to either implement {@link Logging} interface or provide one of the existing implementations available from static factory * methods in the {@link Logging} interface. *

* Please see documentation in {@link Logging} for more information. * * @param logging the logging instance to use * @return this builder * @see Logging */ public ConfigBuilder withLogging(Logging logging) { this.logging = logging; return this; } /** * Enable logging of leaked sessions. *

* Each {@link Session session} is associated with a network connection and thus is a * {@link org.neo4j.driver.util.Resource resource} that needs to be explicitly closed. * Unclosed sessions will result in socket leaks and could cause {@link OutOfMemoryError}s. *

* Session is considered to be leaked when it is finalized via {@link Object#finalize()} while not being * closed. This option turns on logging of such sessions and stacktraces of where they were created. *

* Note: this option should mostly be used in testing environments for session leak investigations. * Enabling it will add object finalization overhead. * * @return this builder */ public ConfigBuilder withLeakedSessionsLogging() { this.logLeakedSessions = true; return this; } /** * Pooled connections that have been idle in the pool for longer than this timeout * will be tested before they are used again, to ensure they are still live. *

* If this option is set too low, an additional network call will be * incurred when acquiring a connection, which causes a performance hit. *

* If this is set high, you may receive sessions that are backed by no longer live connections, * which will lead to exceptions in your application. Assuming the * database is running, these exceptions will go away if you retry acquiring sessions. *

* Hence, this parameter tunes a balance between the likelihood of your * application seeing connection problems, and performance. *

* You normally should not need to tune this parameter. * No connection liveliness check is done by default. * Value {@code 0} means connections will always be tested for * validity and negative values mean connections will never be tested. * * @param value the minimum idle time * @param unit the unit in which the duration is given * @return this builder */ public ConfigBuilder withConnectionLivenessCheckTimeout(long value, TimeUnit unit) { this.idleTimeBeforeConnectionTest = unit.toMillis(value); return this; } /** * Pooled connections older than this threshold will be closed and removed from the pool. Such discarding * happens during connection acquisition so that new session is never backed by an old connection. *

* Setting this option to a low value will cause a high connection churn and might result in a performance hit. *

* It is recommended to set maximum lifetime to a slightly smaller value than the one configured in network * equipment (load balancer, proxy, firewall, etc. can also limit maximum connection lifetime). *

* Setting can also be used in combination with {@link #withConnectionLivenessCheckTimeout(long, TimeUnit)}. In * this case, it is recommended to set liveness check to a value smaller than network equipment has and maximum * lifetime to a reasonably large value to "renew" connections once in a while. *

* Default maximum connection lifetime is 1 hour. Zero and negative values result in lifetime not being * checked. * * @param value the maximum connection lifetime * @param unit the unit in which the duration is given * @return this builder */ public ConfigBuilder withMaxConnectionLifetime(long value, TimeUnit unit) { this.maxConnectionLifetimeMillis = unit.toMillis(value); return this; } /** * Configure maximum amount of connections in the connection pool towards a single database. This setting * limits total amount of connections in the pool when used in direct driver, created for URI with 'bolt' * scheme. It will limit amount of connections per cluster member when used with routing driver, created for * URI with 'neo4j' scheme. *

* Acquisition will be attempted for at most configured timeout * {@link #withConnectionAcquisitionTimeout(long, TimeUnit)} when limit is reached. *

* Default value is {@code 100}. Negative values are allowed and result in unlimited pool. Value of {@code 0} * is not allowed. * * @param value the maximum connection pool size. * @return this builder * @see #withConnectionAcquisitionTimeout(long, TimeUnit) */ public ConfigBuilder withMaxConnectionPoolSize(int value) { if (value == 0) { throw new IllegalArgumentException("Zero value is not supported"); } else if (value < 0) { this.maxConnectionPoolSize = Integer.MAX_VALUE; } else { this.maxConnectionPoolSize = value; } return this; } /** * Configure maximum amount of time connection acquisition will attempt to acquire a connection from the * connection pool. This timeout only kicks in when all existing connections are being used and no new * connections can be created because maximum connection pool size has been reached. *

* Exception is raised when connection can't be acquired within configured time. *

* Default value is 60 seconds. Negative values are allowed and result in unlimited acquisition timeout. Value * of {@code 0} is allowed and results in no timeout and immediate failure when connection is unavailable. * * @param value the acquisition timeout * @param unit the unit in which the duration is given * @return this builder * @see #withMaxConnectionPoolSize(int) */ public ConfigBuilder withConnectionAcquisitionTimeout(long value, TimeUnit unit) { long valueInMillis = unit.toMillis(value); if (value >= 0) { this.connectionAcquisitionTimeoutMillis = valueInMillis; } else { this.connectionAcquisitionTimeoutMillis = -1; } return this; } /** * Set to use encrypted traffic. * @return this builder */ public ConfigBuilder withEncryption() { securitySettingsBuilder.withEncryption(); return this; } /** * Set to use unencrypted traffic. * @return this builder */ public ConfigBuilder withoutEncryption() { securitySettingsBuilder.withoutEncryption(); return this; } /** * Specify how to determine the authenticity of an encryption certificate provided by the Neo4j instance we are connecting to. This defaults to {@link * TrustStrategy#trustSystemCertificates()}. See {@link TrustStrategy#trustCustomCertificateSignedBy(File...)} for using certificate signatures instead to * verify trust. *

* This is an important setting to understand, because unless we know that the remote server we have an encrypted connection to is really Neo4j, there * is no point to encrypt at all, since anyone could pretend to be the remote Neo4j instance. *

* For this reason, there is no option to disable trust verification. However, it is possible to turn off encryption using the {@link * ConfigBuilder#withoutEncryption()} option. * * @param trustStrategy TLS authentication strategy * @return this builder */ public ConfigBuilder withTrustStrategy(TrustStrategy trustStrategy) { securitySettingsBuilder.withTrustStrategy(trustStrategy); return this; } /** * Specify how many times the client should attempt to reconnect to the routing servers before declaring the * cluster unavailable. *

* The routing servers are tried in order. If connecting any of them fails, they are all retried after * {@linkplain #withRoutingRetryDelay a delay}. This process of retrying all servers is then repeated for the * number of times specified here before considering the cluster unavailable. *

* The default value of this parameter is {@code 1}, which means that the the driver will not re-attempt to * connect to the cluster when connecting has failed to each individual server in the list of routers. This * default value is sensible under this assumption that if the attempt to connect fails for all servers, then * the entire cluster is down, or the client is disconnected from the network, and retrying to connect will * not bring it back up, in which case it is better to report the failure sooner. * * @param routingFailureLimit * the number of times to retry each server in the list of routing servers * @return this builder * @deprecated in 1.2 because driver memorizes seed URI used during construction and falls back to it at * runtime when all other known router servers failed to respond. Driver is also able to perform DNS lookup * for the seed URI during rediscovery. This means updates of cluster members will be picked up if they are * reflected in a DNS record. This configuration allowed driver to retry rediscovery procedure and postpone * failure. Currently there exists a better way of doing retries via * {@link Session#readTransaction(TransactionWork)} and {@link Session#writeTransaction(TransactionWork)}. * Method will be removed in the next major release. */ @Deprecated public ConfigBuilder withRoutingFailureLimit(int routingFailureLimit) { if (routingFailureLimit < 1) { throw new IllegalArgumentException( "The failure limit may not be smaller than 1, but was: " + routingFailureLimit); } this.routingFailureLimit = routingFailureLimit; return this; } /** * Specify how long to wait before retrying to connect to a routing server. *

* When connecting to all routing servers fail, connecting will be retried after the delay specified here. * The delay is measured from when the first attempt to connect was made, so that the delay time specifies a * retry interval. *

* For each {@linkplain #withRoutingFailureLimit retry attempt} the delay time will be doubled. The time * specified here is the base time, i.e. the time to wait before the first retry. If that attempt (on all * servers) also fails, the delay before the next retry will be double the time specified here, and the next * attempt after that will be double that, et.c. So if, for example, the delay specified here is * {@code 5 SECONDS}, then after attempting to connect to each server fails reconnecting will be attempted * 5 seconds after the first connection attempt to the first server. If that attempt also fails to connect to * all servers, the next attempt will start 10 seconds after the second attempt started. *

* The default value of this parameter is {@code 5 SECONDS}. * * @param delay * the amount of time between attempts to reconnect to the same server * @param unit * the unit in which the duration is given * @return this builder * @deprecated in 1.2 because driver memorizes seed URI used during construction and falls back to it at * runtime when all other known router servers failed to respond. Driver is also able to perform DNS lookup * for the seed URI during rediscovery. This means updates of cluster members will be picked up if they are * reflected in a DNS record. This configuration allowed driver to retry rediscovery procedure and postpone * failure. Currently there exists a better way of doing retries via * {@link Session#readTransaction(TransactionWork)} and {@link Session#writeTransaction(TransactionWork)}. * Method will be removed in the next major release. */ @Deprecated public ConfigBuilder withRoutingRetryDelay(long delay, TimeUnit unit) { long routingRetryDelayMillis = unit.toMillis(delay); if (routingRetryDelayMillis < 0) { throw new IllegalArgumentException( String.format("The retry delay may not be smaller than 0, but was %d %s.", delay, unit)); } this.routingRetryDelayMillis = routingRetryDelayMillis; return this; } /** * Specify how long to wait before purging stale routing tables. *

* When a routing table is timed out, the routing table will be marked ready to remove after the delay specified here. * Driver keeps a routing table for each database seen by the driver. * The routing table of a database get refreshed if the database is used frequently. * If the database is not used for a long time, * the driver use the timeout specified here to purge the stale routing table. * * After a routing table is removed, next time when using the database of the purged routing table, * the driver will fall back to use seed URI for a new routing table. * @param delay * the amount of time to wait before purging routing tables * @param unit * the unit in which the duration is given * @return this builder */ public ConfigBuilder withRoutingTablePurgeDelay(long delay, TimeUnit unit) { long routingTablePurgeDelayMillis = unit.toMillis(delay); if (routingTablePurgeDelayMillis < 0) { throw new IllegalArgumentException(String.format( "The routing table purge delay may not be smaller than 0, but was %d %s.", delay, unit)); } this.routingTablePurgeDelayMillis = routingTablePurgeDelayMillis; return this; } /** * Specify how many records to fetch in each batch. * This config is only valid when the driver is used with servers that support Bolt V4 (Server version 4.0 and later). * * Bolt V4 enables pulling records in batches to allow client to take control of data population and apply back pressure to server. * This config specifies the default fetch size for all query runs using {@link Session} and {@link org.neo4j.driver.async.AsyncSession}. * By default, the value is set to {@code 1000}. * Use {@code -1} to disables back pressure and config client to pull all records at once after each run. * * This config only applies to run result obtained via {@link Session} and {@link org.neo4j.driver.async.AsyncSession}. * As with {@link org.neo4j.driver.reactive.RxSession}, the batch size is provided via * {@link org.reactivestreams.Subscription#request(long)} instead. * @param size the default record fetch size when pulling records in batches using Bolt V4. * @return this builder */ public ConfigBuilder withFetchSize(long size) { this.fetchSize = FetchSizeUtil.assertValidFetchSize(size); return this; } /** * Specify socket connection timeout. *

* A timeout of zero is treated as an infinite timeout and will be bound by the timeout configured on the * operating system level. The connection will block until established or an error occurs. *

* Timeout value should be greater or equal to zero and represent a valid {@code int} value when converted to * {@link TimeUnit#MILLISECONDS milliseconds}. *

* The default value of this parameter is {@code 30 SECONDS}. * * @param value the timeout duration * @param unit the unit in which duration is given * @return this builder * @throws IllegalArgumentException when given value is negative or does not fit in {@code int} when * converted to milliseconds. */ public ConfigBuilder withConnectionTimeout(long value, TimeUnit unit) { long connectionTimeoutMillis = unit.toMillis(value); if (connectionTimeoutMillis < 0) { throw new IllegalArgumentException( String.format("The connection timeout may not be smaller than 0, but was %d %s.", value, unit)); } int connectionTimeoutMillisInt = (int) connectionTimeoutMillis; if (connectionTimeoutMillisInt != connectionTimeoutMillis) { throw new IllegalArgumentException(String.format( "The connection timeout must represent int value when converted to milliseconds %d.", connectionTimeoutMillis)); } this.connectionTimeoutMillis = connectionTimeoutMillisInt; return this; } /** * Specify the maximum time transactions are allowed to retry via * {@link Session#readTransaction(TransactionWork)} and {@link Session#writeTransaction(TransactionWork)} * methods. These methods will retry the given unit of work on {@link org.neo4j.driver.exceptions.ServiceUnavailableException}, * {@link org.neo4j.driver.exceptions.SessionExpiredException} and {@link org.neo4j.driver.exceptions.TransientException} with * exponential backoff using initial delay of 1 second. *

* Default value is 30 seconds. * * @param value the timeout duration * @param unit the unit in which duration is given * @return this builder * @throws IllegalArgumentException when given value is negative */ public ConfigBuilder withMaxTransactionRetryTime(long value, TimeUnit unit) { long maxRetryTimeMs = unit.toMillis(value); if (maxRetryTimeMs < 0) { throw new IllegalArgumentException( String.format("The max retry time may not be smaller than 0, but was %d %s.", value, unit)); } this.retrySettings = new RetrySettings(maxRetryTimeMs); return this; } /** * Specify a custom server address resolver used by the routing driver to resolve the initial address used to create the driver. * Such resolution happens: *

    *
  • during the very first rediscovery when driver is created
  • *
  • when all the known routers from the current routing table have failed and driver needs to fallback to the initial address
  • *
* By default driver performs a DNS lookup for the initial address using {@link InetAddress#getAllByName(String)}. * * @param resolver the resolver to use. * @return this builder. * @throws NullPointerException when the given resolver is {@code null}. */ public ConfigBuilder withResolver(ServerAddressResolver resolver) { this.resolver = Objects.requireNonNull(resolver, "resolver"); return this; } /** * Enable driver metrics backed by internal basic implementation. The metrics can be obtained afterwards via {@link Driver#metrics()}. * * @return this builder. */ public ConfigBuilder withDriverMetrics() { return withMetricsEnabled(true); } /** * Disable driver metrics. When disabled, driver metrics cannot be accessed via {@link Driver#metrics()}. * @return this builder. */ public ConfigBuilder withoutDriverMetrics() { return withMetricsEnabled(false); } private ConfigBuilder withMetricsEnabled(boolean enabled) { if (!enabled) { withMetricsAdapter(MetricsAdapter.DEV_NULL); } else if (this.metricsAdapter == null || this.metricsAdapter == MetricsAdapter.DEV_NULL) { withMetricsAdapter(MetricsAdapter.DEFAULT); } return this; } /** * Enable driver metrics with given {@link MetricsAdapter}. *

* {@link MetricsAdapter#MICROMETER} enables implementation based on Micrometer. The metrics can be obtained * afterwards via Micrometer means and {@link Driver#metrics()}. Micrometer must be on classpath when using this option. *

* * @param metricsAdapter the metrics adapter to use. Use {@link MetricsAdapter#DEV_NULL} to disable metrics. * @return this builder. */ @Experimental public ConfigBuilder withMetricsAdapter(MetricsAdapter metricsAdapter) { this.metricsAdapter = Objects.requireNonNull(metricsAdapter, "metricsAdapter"); return this; } /** * Configure the event loop thread count. This specifies how many threads the driver can use to handle network I/O events * and user's events in driver's I/O threads. By default, 2 * NumberOfProcessors amount of threads will be used instead. * @param size the thread count. * @return this builder. * @throws IllegalArgumentException if the value of the size is set to a number that is less than 1. */ public ConfigBuilder withEventLoopThreads(int size) { if (size < 1) { throw new IllegalArgumentException( String.format("The event loop thread may not be smaller than 1, but was %d.", size)); } this.eventLoopThreads = size; return this; } /** * Configure the user_agent field sent to the server to identify the connected client. * @param userAgent the string to configure user_agent. * @return this builder. */ public ConfigBuilder withUserAgent(String userAgent) { if (userAgent == null || userAgent.isEmpty()) { throw new IllegalArgumentException("The user_agent string must not be empty"); } this.userAgent = userAgent; return this; } /** * Extracts the driver version from the driver jar MANIFEST.MF file. */ private static String driverVersion() { // "Session" is arbitrary - the only thing that matters is that the class we use here is in the // 'org.neo4j.driver' package, because that is where the jar manifest specifies the version. // This is done as part of the build, adding a MANIFEST.MF file to the generated jarfile. Package pkg = Session.class.getPackage(); if (pkg != null && pkg.getImplementationVersion() != null) { return pkg.getImplementationVersion(); } // If there is no version, we're not running from a jar file, but from raw compiled class files. // This should only happen during development, so call the version 'dev'. return "dev"; } /** * Create a config instance from this builder. * * @return a new {@link Config} instance. */ public Config build() { return new Config(this); } } /** * Control how the driver determines if it can trust the encryption certificates provided by the Neo4j instance it is connected to. */ public static class TrustStrategy implements Serializable { private static final long serialVersionUID = -1631888096243987740L; /** * The trust strategy that the driver supports */ public enum Strategy { TRUST_ALL_CERTIFICATES, TRUST_CUSTOM_CA_SIGNED_CERTIFICATES, TRUST_SYSTEM_CA_SIGNED_CERTIFICATES } private final Strategy strategy; private final List certFiles; private boolean hostnameVerificationEnabled = true; private RevocationCheckingStrategy revocationCheckingStrategy = RevocationCheckingStrategy.NO_CHECKS; private TrustStrategy(Strategy strategy) { this(strategy, Collections.emptyList()); } private TrustStrategy(Strategy strategy, List certFiles) { Objects.requireNonNull(certFiles, "certFiles can't be null"); this.strategy = strategy; this.certFiles = Collections.unmodifiableList(new ArrayList<>(certFiles)); } /** * Return the strategy type desired. * * @return the strategy we should use */ public Strategy strategy() { return strategy; } /** * Return the configured certificate file. * * @return configured certificate or {@code null} if trust strategy does not require a certificate. * @deprecated superseded by {@link TrustStrategy#certFiles()} */ @Deprecated public File certFile() { return certFiles.isEmpty() ? null : certFiles.get(0); } /** * Return the configured certificate files. * * @return configured certificate files or empty list if trust strategy does not require certificates. */ public List certFiles() { return certFiles; } /** * Check if hostname verification is enabled for this trust strategy. * * @return {@code true} if hostname verification has been enabled via {@link #withHostnameVerification()}, {@code false} otherwise. */ public boolean isHostnameVerificationEnabled() { return hostnameVerificationEnabled; } /** * Enable hostname verification for this trust strategy. * * @return the current trust strategy. */ public TrustStrategy withHostnameVerification() { hostnameVerificationEnabled = true; return this; } /** * Disable hostname verification for this trust strategy. * * @return the current trust strategy. */ public TrustStrategy withoutHostnameVerification() { hostnameVerificationEnabled = false; return this; } /** * Only encrypted connections to Neo4j instances with certificates signed by a trusted certificate will be accepted. The file(s) specified should * contain one or more trusted X.509 certificates. *

* The certificate(s) in the file(s) must be encoded using PEM encoding, meaning the certificates in the file(s) should be encoded using Base64, and * each certificate is bounded at the beginning by "-----BEGIN CERTIFICATE-----", and bounded at the end by "-----END CERTIFICATE-----". * * @param certFiles the trusted certificate files, it must not be {@code null} or empty * @return an authentication config */ public static TrustStrategy trustCustomCertificateSignedBy(File... certFiles) { Objects.requireNonNull(certFiles, "certFiles can't be null"); if (certFiles.length == 0) { throw new IllegalArgumentException("certFiles can't be empty"); } return new TrustStrategy(Strategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES, Arrays.asList(certFiles)); } /** * Trust strategy for certificates that can be verified through the local system store. * * @return an authentication config */ public static TrustStrategy trustSystemCertificates() { return new TrustStrategy(Strategy.TRUST_SYSTEM_CA_SIGNED_CERTIFICATES); } /** * Trust strategy for certificates that trust all certificates blindly. Suggested to only use this in tests. * * @return an authentication config * @since 1.1 */ public static TrustStrategy trustAllCertificates() { return new TrustStrategy(Strategy.TRUST_ALL_CERTIFICATES); } /** * The revocation strategy used for verifying certificates. * @return this {@link TrustStrategy}'s revocation strategy */ public RevocationCheckingStrategy revocationCheckingStrategy() { return revocationCheckingStrategy; } /** * The revocation strategy used for verifying certificates. * @return this {@link TrustStrategy}'s revocation strategy * @deprecated superseded by {@link TrustStrategy#revocationCheckingStrategy()} */ @Deprecated public RevocationStrategy revocationStrategy() { RevocationStrategy revocationStrategy; switch (this.revocationCheckingStrategy) { case VERIFY_IF_PRESENT: revocationStrategy = RevocationStrategy.VERIFY_IF_PRESENT; break; case STRICT: revocationStrategy = RevocationStrategy.STRICT; break; case NO_CHECKS: revocationStrategy = RevocationStrategy.NO_CHECKS; break; default: throw new IllegalStateException("Failed to map RevocationCheckingStrategy to RevocationStrategy."); } return revocationStrategy; } /** * Configures the {@link TrustStrategy} to not carry out OCSP revocation checks on certificates. This is the * option that is configured by default. * @return the current trust strategy */ public TrustStrategy withoutCertificateRevocationChecks() { this.revocationCheckingStrategy = RevocationCheckingStrategy.NO_CHECKS; return this; } /** * Configures the {@link TrustStrategy} to carry out OCSP revocation checks when the revocation status is * stapled to the certificate. If no stapled response is found, then certificate verification continues * (and does not fail verification). This setting also requires the server to be configured to enable * OCSP stapling. * @return the current trust strategy */ public TrustStrategy withVerifyIfPresentRevocationChecks() { this.revocationCheckingStrategy = RevocationCheckingStrategy.VERIFY_IF_PRESENT; return this; } /** * Configures the {@link TrustStrategy} to carry out strict OCSP revocation checks for revocation status that * are stapled to the certificate. If no stapled response is found, then the driver will fail certificate verification * and not connect to the server. This setting also requires the server to be configured to enable OCSP stapling. * * Note: enabling this setting will prevent the driver connecting to the server when the server is unable to reach * the certificate's configured OCSP responder URL. * @return the current trust strategy */ public TrustStrategy withStrictRevocationChecks() { this.revocationCheckingStrategy = RevocationCheckingStrategy.STRICT; return this; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy