diff --git a/community/bolt/src/main/java/org/neo4j/bolt/BoltServer.java b/community/bolt/src/main/java/org/neo4j/bolt/BoltServer.java index c2ae7796692e2..9f05a29a31045 100644 --- a/community/bolt/src/main/java/org/neo4j/bolt/BoltServer.java +++ b/community/bolt/src/main/java/org/neo4j/bolt/BoltServer.java @@ -119,7 +119,7 @@ public void start() throws Throwable BoltProtocolFactory boltProtocolFactory = createBoltProtocolFactory( boltConnectionFactory, boltStateMachineFactory ); - if ( !config.enabledBoltConnectors().isEmpty() && !config.get( GraphDatabaseSettings.disconnected ) ) + if ( !config.enabledBoltConnectors().isEmpty() ) { NettyServer server = new NettyServer( jobScheduler.threadFactory( Group.BOLT_NETWORK_IO ), createConnectors( boltProtocolFactory, throttleGroup, log ), connectorPortRegister, userLog ); diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java index d168c33c1c6c0..42f1bde2058d6 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java @@ -146,11 +146,6 @@ public class GraphDatabaseSettings implements LoadableConfig @Internal public static final Setting editionName = setting( "unsupported.dbms.edition", STRING, Edition.unknown.toString() ); - @Title( "Disconnected" ) - @Internal - @Description( "Disable all protocol connectors." ) - public static final Setting disconnected = setting( "unsupported.dbms.disconnected", BOOLEAN, FALSE ); - @Description( "Print out the effective Neo4j configuration after startup." ) @Internal public static final Setting dump_configuration = setting( "unsupported.dbms.report_configuration", diff --git a/community/kernel/src/main/java/org/neo4j/helpers/PortBindException.java b/community/kernel/src/main/java/org/neo4j/helpers/PortBindException.java index e517f5c867c2a..d0a16dfee7360 100644 --- a/community/kernel/src/main/java/org/neo4j/helpers/PortBindException.java +++ b/community/kernel/src/main/java/org/neo4j/helpers/PortBindException.java @@ -30,13 +30,28 @@ public class PortBindException extends BindException { public PortBindException( ListenSocketAddress address, Throwable original ) { - super( String.format("Address %s is already in use, cannot bind to it.", address) ); - setStackTrace( original.getStackTrace() ); + this( address, null, original ); } - public PortBindException( ListenSocketAddress address, ListenSocketAddress other, Throwable original ) + public PortBindException( ListenSocketAddress address1, ListenSocketAddress address2, Throwable original ) { - super( String.format("At least one of the addresses %s or %s is already in use, cannot bind to it.", address, other) ); + super( createMessage( address1, address2 ) ); setStackTrace( original.getStackTrace() ); } + + private static String createMessage( ListenSocketAddress address1, ListenSocketAddress address2 ) + { + if ( address1 == null && address2 == null ) + { + throw new IllegalArgumentException( "At least one address should not be null" ); + } + else if ( address1 != null && address2 != null ) + { + return String.format( "At least one of the addresses %s or %s is already in use, cannot bind to it.", address1, address2 ); + } + else + { + return String.format( "Address %s is already in use, cannot bind to it.", address1 != null ? address1 : address2 ); + } + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/configuration/Config.java b/community/kernel/src/main/java/org/neo4j/kernel/configuration/Config.java index 0d87fc4870d32..ffdcd58e0586a 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/configuration/Config.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/configuration/Config.java @@ -44,8 +44,6 @@ import org.neo4j.configuration.ConfigOptions; import org.neo4j.configuration.ConfigValue; import org.neo4j.configuration.LoadableConfig; -import org.neo4j.internal.diagnostics.DiagnosticsPhase; -import org.neo4j.internal.diagnostics.DiagnosticsProvider; import org.neo4j.graphdb.config.BaseSetting; import org.neo4j.graphdb.config.Configuration; import org.neo4j.graphdb.config.InvalidSettingException; @@ -53,6 +51,8 @@ import org.neo4j.graphdb.config.SettingValidator; import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.helpers.collection.MapUtil; +import org.neo4j.internal.diagnostics.DiagnosticsPhase; +import org.neo4j.internal.diagnostics.DiagnosticsProvider; import org.neo4j.kernel.configuration.HttpConnector.Encryption; import org.neo4j.kernel.impl.util.CopyOnWriteHashMap; import org.neo4j.logging.BufferingLog; @@ -208,9 +208,6 @@ public Builder withServerDefaults() overriddenDefaults.put( https.enabled.name(), TRUE ); overriddenDefaults.put( bolt.enabled.name(), TRUE ); - // Add server validator - validators.add( new ServerConfigurationValidator() ); - return this; } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ServerConfigurationValidator.java b/community/kernel/src/main/java/org/neo4j/kernel/configuration/ServerConfigurationValidator.java deleted file mode 100644 index 1d50687b26887..0000000000000 --- a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ServerConfigurationValidator.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2002-2018 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.kernel.configuration; - -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nonnull; - -import org.neo4j.graphdb.config.InvalidSettingException; -import org.neo4j.logging.Log; - -import static org.neo4j.kernel.configuration.Connector.ConnectorType.BOLT; -import static org.neo4j.kernel.configuration.Connector.ConnectorType.HTTP; - - -public class ServerConfigurationValidator implements ConfigurationValidator -{ - /** - * Verifies that at least one http connector is specified and enabled. - */ - @Override - public Map validate( @Nonnull Config config, @Nonnull Log log ) throws InvalidSettingException - { - Map validSettings = new HashMap<>(); - - // Add missing type info -- validation has succeeded so we can do this with confidence - boolean hasEnabledConnector = false; - for ( String identifier : config.identifiersFromGroup( Connector.class ) ) - { - Connector connector = new Connector( identifier ); - if ( "http".equalsIgnoreCase( connector.group.groupKey ) || "https".equalsIgnoreCase( connector.group.groupKey ) ) - { - validSettings.put( connector.type.name(), HTTP.name() ); - hasEnabledConnector = hasEnabledConnector ? true : config.get( connector.enabled ); - } - else - { - validSettings.put( connector.type.name(), BOLT.name() ); - } - } - - if ( !hasEnabledConnector ) - { - throw new InvalidSettingException( String.format( "Missing mandatory enabled connector of type '%s'", HTTP ) ); - } - - return validSettings; - } -} diff --git a/community/kernel/src/test/java/org/neo4j/kernel/configuration/ServerConfigurationValidatorTest.java b/community/kernel/src/test/java/org/neo4j/kernel/configuration/ServerConfigurationValidatorTest.java deleted file mode 100644 index f1201a88e5ad4..0000000000000 --- a/community/kernel/src/test/java/org/neo4j/kernel/configuration/ServerConfigurationValidatorTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2002-2018 "Neo4j," - * Neo4j Sweden AB [http://neo4j.com] - * - * This file is part of Neo4j. - * - * Neo4j is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.neo4j.kernel.configuration; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import org.neo4j.graphdb.config.InvalidSettingException; - -import static org.neo4j.helpers.collection.MapUtil.stringMap; - -public class ServerConfigurationValidatorTest -{ - @Rule - public ExpectedException expected = ExpectedException.none(); - - @Test - public void httpConnectorIsRequired() - { - // then - expected.expect( InvalidSettingException.class ); - expected.expectMessage( "Missing mandatory enabled connector of type 'HTTP'" ); - - // when - Config.fromSettings( - stringMap( "dbms.connector.http.enabled", "false", - "dbms.connector.https.enabled", "false") ).withServerDefaults().build(); - } -} diff --git a/community/server-plugin-test/src/test/java/org/neo4j/server/plugins/PluginManagerTest.java b/community/server-plugin-test/src/test/java/org/neo4j/server/plugins/DefaultPluginManagerTest.java similarity index 95% rename from community/server-plugin-test/src/test/java/org/neo4j/server/plugins/PluginManagerTest.java rename to community/server-plugin-test/src/test/java/org/neo4j/server/plugins/DefaultPluginManagerTest.java index f2c5c73b2a637..f706faf38dbb4 100644 --- a/community/server-plugin-test/src/test/java/org/neo4j/server/plugins/PluginManagerTest.java +++ b/community/server-plugin-test/src/test/java/org/neo4j/server/plugins/DefaultPluginManagerTest.java @@ -19,14 +19,14 @@ */ package org.neo4j.server.plugins; -import java.util.List; -import java.util.Map; -import javax.ws.rs.core.MediaType; - import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.MediaType; + import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.neo4j.logging.NullLogProvider; @@ -37,7 +37,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; -public class PluginManagerTest +public class DefaultPluginManagerTest { private static PluginManager manager; private static GraphDatabaseAPI graphDb; @@ -46,7 +46,7 @@ public class PluginManagerTest public static void loadExtensionManager() { graphDb = (GraphDatabaseAPI) new TestGraphDatabaseFactory().newImpermanentDatabase(); - manager = new PluginManager( null, NullLogProvider.getInstance() ); + manager = new DefaultPluginManager( NullLogProvider.getInstance() ); } @AfterClass diff --git a/community/server/src/main/java/org/neo4j/server/AbstractNeoServer.java b/community/server/src/main/java/org/neo4j/server/AbstractNeoServer.java index 833714e9bba3d..8ab9f3c04a07d 100644 --- a/community/server/src/main/java/org/neo4j/server/AbstractNeoServer.java +++ b/community/server/src/main/java/org/neo4j/server/AbstractNeoServer.java @@ -32,12 +32,12 @@ import java.util.function.Supplier; import java.util.regex.Pattern; -import org.neo4j.internal.diagnostics.DiagnosticsManager; import org.neo4j.graphdb.DependencyResolver; import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; import org.neo4j.helpers.AdvertisedSocketAddress; import org.neo4j.helpers.ListenSocketAddress; import org.neo4j.helpers.RunCarefully; +import org.neo4j.internal.diagnostics.DiagnosticsManager; import org.neo4j.io.fs.FileSystemAbstraction; import org.neo4j.kernel.GraphDatabaseQueryService; import org.neo4j.kernel.api.security.AuthManager; @@ -61,7 +61,9 @@ import org.neo4j.server.database.Database; import org.neo4j.server.database.DatabaseProvider; import org.neo4j.server.database.GraphDatabaseServiceProvider; +import org.neo4j.server.database.GraphFactory; import org.neo4j.server.database.InjectableProvider; +import org.neo4j.server.database.LifecycleManagingDatabase; import org.neo4j.server.modules.RESTApiModule; import org.neo4j.server.modules.ServerModule; import org.neo4j.server.plugins.ConfigAdapter; @@ -112,7 +114,7 @@ public abstract class AbstractNeoServer implements NeoServer }; public static final String NEO4J_IS_STARTING_MESSAGE = "======== Neo4j " + Version.getNeo4jVersion() + " ========"; - private final Database.Factory dbFactory; + private final GraphFactory graphFactory; private final GraphDatabaseFacadeFactory.Dependencies dependencies; protected final LogProvider logProvider; protected final Log log; @@ -122,9 +124,9 @@ public abstract class AbstractNeoServer implements NeoServer private final Config config; private final LifeSupport life = new LifeSupport(); private final ListenSocketAddress httpListenAddress; - private final Optional httpsListenAddress; + private final ListenSocketAddress httpsListenAddress; private AdvertisedSocketAddress httpAdvertisedAddress; - private Optional httpsAdvertisedAddress; + private AdvertisedSocketAddress httpsAdvertisedAddress; protected Database database; private DependencyResolver dependencyResolver; @@ -137,63 +139,44 @@ public abstract class AbstractNeoServer implements NeoServer private TransactionFacade transactionFacade; private TransactionHandleRegistry transactionRegistry; - private boolean initialized; private ConnectorPortRegister connectorPortRegister; private HttpConnector httpConnector; - private Optional httpsConnector; + private HttpConnector httpsConnector; private AsyncRequestLog requestLog; protected abstract Iterable createServerModules(); protected abstract WebServer createWebServer(); - public AbstractNeoServer( Config config, Database.Factory dbFactory, + public AbstractNeoServer( Config config, GraphFactory graphFactory, GraphDatabaseFacadeFactory.Dependencies dependencies, LogProvider logProvider ) { this.config = config; - this.dbFactory = dbFactory; + this.graphFactory = graphFactory; this.dependencies = dependencies; this.logProvider = logProvider; this.log = logProvider.getLog( getClass() ); log.info( NEO4J_IS_STARTING_MESSAGE ); - List httpConnectors = config.enabledHttpConnectors(); - - httpConnector = httpConnectors.stream() - .filter( c -> Encryption.NONE.equals( c.encryptionLevel() ) ) - .findFirst().orElseThrow( () -> - new IllegalArgumentException( "An HTTP connector must be configured to run the server" ) ); + verifyConnectorsConfiguration( config ); - httpListenAddress = config.get( httpConnector.listen_address ); - httpAdvertisedAddress = config.get( httpConnector.advertised_address ); + httpConnector = findConnector( config, Encryption.NONE ); + httpListenAddress = listenAddressFor( config, httpConnector ); + httpAdvertisedAddress = advertisedAddressFor( config, httpConnector ); - httpsConnector = httpConnectors.stream() - .filter( c -> Encryption.TLS.equals( c.encryptionLevel() ) ) - .findFirst(); - httpsListenAddress = httpsConnector.map( connector -> config.get( connector.listen_address ) ); - httpsAdvertisedAddress = httpsConnector.map( connector -> config.get( connector.advertised_address ) ); + httpsConnector = findConnector( config, Encryption.TLS ); + httpsListenAddress = listenAddressFor( config, httpsConnector ); + httpsAdvertisedAddress = advertisedAddressFor( config, httpsConnector ); } @Override - public void init() + public void start() throws ServerStartupException { - if ( initialized ) - { - return; - } - - this.database = dbFactory.newDatabase( config, dependencies ); + database = new LifecycleManagingDatabase( config, graphFactory, dependencies ); life.add( database ); life.add( new ServerDependenciesLifeCycleAdapter() ); life.add( new ServerComponentsLifecycleAdapter() ); - this.initialized = true; - } - - @Override - public void start() throws ServerStartupException - { - init(); try { life.start(); @@ -288,7 +271,7 @@ public Config getConfig() private void configureWebServer() { - webServer.setAddress( httpListenAddress ); + webServer.setHttpAddress( httpListenAddress ); webServer.setHttpsAddress( httpsListenAddress ); webServer.setMaxThreads( config.get( ServerSettings.webserver_max_threads ) ); webServer.setWadlEnabled( config.get( ServerSettings.wadl_enabled ) ); @@ -308,39 +291,41 @@ private void startWebServer() throws Exception { setUpHttpLogging(); webServer.start(); - InetSocketAddress localHttpAddress = webServer.getLocalHttpAddress(); - connectorPortRegister.register( httpConnector.key(), localHttpAddress ); - httpsConnector.ifPresent( connector -> connectorPortRegister.register( connector.key(), webServer - .getLocalHttpsAddress() ) ); - checkHttpAdvertisedAddress( localHttpAddress ); - checkHttpsAdvertisedAddress(); + registerHttpAddressAfterStartup(); + registerHttpsAddressAfterStartup(); log.info( "Remote interface available at %s", baseUri() ); } catch ( Exception e ) { - log.error( "Failed to start Neo4j on %s: %s", getAddress(), e.getMessage() ); + ListenSocketAddress address = httpListenAddress != null ? httpListenAddress : httpsListenAddress; + log.error( "Failed to start Neo4j on %s: %s", address, e.getMessage() ); throw e; } } - private void checkHttpsAdvertisedAddress() + private void registerHttpAddressAfterStartup() { - httpsAdvertisedAddress.ifPresent( address -> + if ( httpConnector != null ) { - if ( address.getPort() == 0 ) + InetSocketAddress localHttpAddress = webServer.getLocalHttpAddress(); + connectorPortRegister.register( httpConnector.key(), localHttpAddress ); + if ( httpAdvertisedAddress.getPort() == 0 ) { - InetSocketAddress localHttpsAddress = webServer.getLocalHttpsAddress(); - httpsAdvertisedAddress = Optional - .of( new AdvertisedSocketAddress( localHttpsAddress.getHostString(), localHttpsAddress.getPort() ) ); + httpAdvertisedAddress = new AdvertisedSocketAddress( localHttpAddress.getHostString(), localHttpAddress.getPort() ); } - } ); + } } - private void checkHttpAdvertisedAddress( InetSocketAddress localHttpAddress ) + private void registerHttpsAddressAfterStartup() { - if ( httpAdvertisedAddress.getPort() == 0 ) + if ( httpsConnector != null ) { - httpAdvertisedAddress = new AdvertisedSocketAddress( localHttpAddress.getHostString(), localHttpAddress.getPort() ); + InetSocketAddress localHttpsAddress = webServer.getLocalHttpsAddress(); + connectorPortRegister.register( httpsConnector.key(), localHttpsAddress ); + if ( httpsAdvertisedAddress.getPort() == 0 ) + { + httpsAdvertisedAddress = new AdvertisedSocketAddress( localHttpsAddress.getHostString(), localHttpsAddress.getPort() ); + } } } @@ -360,16 +345,6 @@ private void setUpHttpLogging() throws IOException webServer.setRequestLog( requestLog ); } - public ListenSocketAddress getAddress() - { - return httpListenAddress; - } - - protected boolean httpsIsEnabled() - { - return httpsListenAddress.isPresent(); - } - protected Pattern[] getUriWhitelist() { return DEFAULT_URI_WHITELIST; @@ -378,7 +353,11 @@ protected Pattern[] getUriWhitelist() @Override public void stop() { + // Stop and clear the nested life. + // It needs to be cleared because server can be restarted, for example using a JMX bean. + // See `ServerManagementMBean` and its implementation. life.stop(); + life.clear(); } private void stopWebServer() throws Exception @@ -408,12 +387,15 @@ public TransactionRegistry getTransactionRegistry() @Override public URI baseUri() { - return uriBuilder.buildURI( httpAdvertisedAddress, false ); + return httpAdvertisedAddress != null + ? uriBuilder.buildURI( httpAdvertisedAddress, false ) + : uriBuilder.buildURI( httpsAdvertisedAddress, true ); } public Optional httpsUri() { - return httpsAdvertisedAddress.map( address -> uriBuilder.buildURI( address, true ) ); + return Optional.ofNullable( httpsAdvertisedAddress ) + .map( address -> uriBuilder.buildURI( address, true ) ); } public WebServer getWebServer() @@ -485,6 +467,36 @@ protected T resolveDependency( Class type ) return dependencyResolver.resolveDependency( type ); } + private static void verifyConnectorsConfiguration( Config config ) + { + HttpConnector httpConnector = findConnector( config, Encryption.NONE ); + HttpConnector httpsConnector = findConnector( config, Encryption.TLS ); + + if ( httpConnector == null && httpsConnector == null ) + { + throw new IllegalArgumentException( "Either HTTP or HTTPS connector must be configured to run the server" ); + } + } + + private static HttpConnector findConnector( Config config, Encryption encryption ) + { + return config.enabledHttpConnectors() + .stream() + .filter( connector -> connector.encryptionLevel() == encryption ) + .findFirst() + .orElse( null ); + } + + private static ListenSocketAddress listenAddressFor( Config config, HttpConnector connector ) + { + return connector == null ? null : config.get( connector.listen_address ); + } + + private static AdvertisedSocketAddress advertisedAddressFor( Config config, HttpConnector connector ) + { + return connector == null ? null : config.get( connector.advertised_address ); + } + private class ServerDependenciesLifeCycleAdapter extends LifecycleAdapter { @Override diff --git a/community/server/src/main/java/org/neo4j/server/CommunityBootstrapper.java b/community/server/src/main/java/org/neo4j/server/CommunityBootstrapper.java index 4204028d34d38..d2cec139602c4 100644 --- a/community/server/src/main/java/org/neo4j/server/CommunityBootstrapper.java +++ b/community/server/src/main/java/org/neo4j/server/CommunityBootstrapper.java @@ -19,29 +19,23 @@ */ package org.neo4j.server; -import java.util.Collection; -import java.util.Collections; -import javax.annotation.Nonnull; - import org.neo4j.graphdb.facade.GraphDatabaseDependencies; import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.configuration.ConfigurationValidator; -import org.neo4j.kernel.configuration.ServerConfigurationValidator; import org.neo4j.logging.LogProvider; +import org.neo4j.server.database.CommunityGraphFactory; +import org.neo4j.server.database.GraphFactory; public class CommunityBootstrapper extends ServerBootstrapper { @Override - protected NeoServer createNeoServer( Config config, GraphDatabaseDependencies dependencies, - LogProvider logProvider ) + protected GraphFactory createGraphFactory( Config config ) { - return new CommunityNeoServer( config, dependencies, logProvider ); + return new CommunityGraphFactory(); } @Override - @Nonnull - protected Collection configurationValidators() + protected NeoServer createNeoServer( GraphFactory graphFactory, Config config, GraphDatabaseDependencies dependencies, LogProvider userLogProvider ) { - return Collections.singletonList( new ServerConfigurationValidator() ); + return new CommunityNeoServer( config, graphFactory, dependencies, userLogProvider ); } } diff --git a/community/server/src/main/java/org/neo4j/server/CommunityNeoServer.java b/community/server/src/main/java/org/neo4j/server/CommunityNeoServer.java index b4812d86623ed..12e74f88738c6 100644 --- a/community/server/src/main/java/org/neo4j/server/CommunityNeoServer.java +++ b/community/server/src/main/java/org/neo4j/server/CommunityNeoServer.java @@ -19,22 +19,17 @@ */ package org.neo4j.server; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Supplier; -import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; -import org.neo4j.graphdb.factory.module.edition.CommunityEditionModule; import org.neo4j.kernel.api.net.NetworkConnectionTracker; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.ConnectorPortRegister; -import org.neo4j.kernel.impl.factory.DatabaseInfo; import org.neo4j.logging.LogProvider; -import org.neo4j.server.database.Database; -import org.neo4j.server.database.LifecycleManagingDatabase.GraphFactory; +import org.neo4j.server.database.CommunityGraphFactory; +import org.neo4j.server.database.GraphFactory; import org.neo4j.server.modules.AuthorizationModule; import org.neo4j.server.modules.ConsoleModule; import org.neo4j.server.modules.DBMSModule; @@ -52,28 +47,19 @@ import org.neo4j.server.web.WebServer; import org.neo4j.udc.UsageData; -import static org.neo4j.server.database.LifecycleManagingDatabase.lifecycleManagingDatabase; +import static org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; import static org.neo4j.server.rest.discovery.CommunityDiscoverableURIs.communityDiscoverableURIs; public class CommunityNeoServer extends AbstractNeoServer { - protected static final GraphFactory COMMUNITY_FACTORY = ( config, dependencies ) -> + public CommunityNeoServer( Config config, Dependencies dependencies, LogProvider logProvider ) { - File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); - return new GraphDatabaseFacadeFactory( DatabaseInfo.COMMUNITY, CommunityEditionModule::new ) - .newFacade( storeDir, config, dependencies ); - }; - - public CommunityNeoServer( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies, - LogProvider logProvider ) - { - this( config, lifecycleManagingDatabase( COMMUNITY_FACTORY ), dependencies, logProvider ); + this( config, new CommunityGraphFactory(), dependencies, logProvider ); } - public CommunityNeoServer( Config config, Database.Factory dbFactory, GraphDatabaseFacadeFactory.Dependencies - dependencies, LogProvider logProvider ) + public CommunityNeoServer( Config config, GraphFactory graphFactory, Dependencies dependencies, LogProvider logProvider ) { - super( config, dbFactory, dependencies, logProvider ); + super( config, graphFactory, dependencies, logProvider ); } @Override diff --git a/community/server/src/main/java/org/neo4j/server/DisabledNeoServer.java b/community/server/src/main/java/org/neo4j/server/DisabledNeoServer.java new file mode 100644 index 0000000000000..fd7d213710635 --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/DisabledNeoServer.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server; + +import java.net.URI; +import java.util.Collections; + +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.lifecycle.LifeSupport; +import org.neo4j.logging.LogProvider; +import org.neo4j.server.database.Database; +import org.neo4j.server.database.GraphFactory; +import org.neo4j.server.database.LifecycleManagingDatabase; +import org.neo4j.server.plugins.DisabledPluginManager; +import org.neo4j.server.plugins.PluginManager; +import org.neo4j.server.rest.management.AdvertisableService; +import org.neo4j.server.rest.transactional.DisabledTransactionRegistry; +import org.neo4j.server.rest.transactional.TransactionRegistry; + +import static org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; +import static org.neo4j.server.AbstractNeoServer.NEO4J_IS_STARTING_MESSAGE; +import static org.neo4j.server.exception.ServerStartupErrors.translateToServerStartupError; + +class DisabledNeoServer implements NeoServer +{ + private final GraphFactory graphFactory; + private final Dependencies dependencies; + private final Config config; + + private Database db; + private final LifeSupport life = new LifeSupport(); + + DisabledNeoServer( GraphFactory graphFactory, Dependencies dependencies, Config config, LogProvider logProvider ) + { + this.graphFactory = graphFactory; + this.dependencies = dependencies; + this.config = config; + logProvider.getLog( getClass() ).info( NEO4J_IS_STARTING_MESSAGE ); + } + + @Override + public void start() + { + db = new LifecycleManagingDatabase( config, graphFactory, dependencies ); + life.add( db ); + + try + { + life.start(); + } + catch ( Throwable t ) + { + life.shutdown(); + throw translateToServerStartupError( t ); + } + } + + @Override + public void stop() + { + life.stop(); + } + + @Override + public Config getConfig() + { + return config; + } + + @Override + public Database getDatabase() + { + return db; + } + + @Override + public TransactionRegistry getTransactionRegistry() + { + return DisabledTransactionRegistry.INSTANCE; + } + + @Override + public PluginManager getExtensionManager() + { + return DisabledPluginManager.INSTANCE; + } + + @Override + public URI baseUri() + { + throw new UnsupportedOperationException( "Neo4j server is disabled" ); + } + + @Override + public Iterable getServices() + { + return Collections.emptyList(); + } +} diff --git a/community/server/src/main/java/org/neo4j/server/NeoServer.java b/community/server/src/main/java/org/neo4j/server/NeoServer.java index 19e5b0392e681..049667538e553 100644 --- a/community/server/src/main/java/org/neo4j/server/NeoServer.java +++ b/community/server/src/main/java/org/neo4j/server/NeoServer.java @@ -29,8 +29,6 @@ public interface NeoServer { - void init(); - void start(); void stop(); diff --git a/community/server/src/main/java/org/neo4j/server/ServerBootstrapper.java b/community/server/src/main/java/org/neo4j/server/ServerBootstrapper.java index d4d55aecddb9b..f3d6d5ea6f7e8 100644 --- a/community/server/src/main/java/org/neo4j/server/ServerBootstrapper.java +++ b/community/server/src/main/java/org/neo4j/server/ServerBootstrapper.java @@ -23,11 +23,11 @@ import java.io.File; import java.util.Collection; +import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; -import javax.annotation.Nonnull; import org.neo4j.graphdb.TransactionFailureException; import org.neo4j.graphdb.facade.GraphDatabaseDependencies; @@ -40,6 +40,7 @@ import org.neo4j.logging.FormattedLogProvider; import org.neo4j.logging.Log; import org.neo4j.logging.LogProvider; +import org.neo4j.server.database.GraphFactory; import org.neo4j.server.logging.JULBridge; import org.neo4j.server.logging.JettyLogBridge; @@ -164,11 +165,30 @@ public NeoServer getServer() return server; } - protected abstract NeoServer createNeoServer( Config config, GraphDatabaseDependencies dependencies, - LogProvider userLogProvider ); + private NeoServer createNeoServer( Config config, GraphDatabaseDependencies dependencies, LogProvider userLogProvider ) + { + GraphFactory graphFactory = createGraphFactory( config ); + + boolean httpAndHttpsDisabled = config.enabledHttpConnectors().isEmpty(); + if ( httpAndHttpsDisabled ) + { + return new DisabledNeoServer( graphFactory, dependencies, config, userLogProvider ); + } + return createNeoServer( graphFactory, config, dependencies, userLogProvider ); + } - @Nonnull - protected abstract Collection configurationValidators(); + protected abstract GraphFactory createGraphFactory( Config config ); + + /** + * Create a new server component. This method is invoked only when at least one HTTP connector is enabled. + */ + protected abstract NeoServer createNeoServer( GraphFactory graphFactory, Config config, GraphDatabaseDependencies dependencies, + LogProvider userLogProvider ); + + protected Collection configurationValidators() + { + return Collections.emptyList(); + } private static LogProvider setupLogging( Config config ) { diff --git a/community/server/src/main/java/org/neo4j/server/database/CommunityGraphFactory.java b/community/server/src/main/java/org/neo4j/server/database/CommunityGraphFactory.java new file mode 100644 index 0000000000000..99f82b70b4e06 --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/database/CommunityGraphFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.database; + +import java.io.File; + +import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; +import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.graphdb.factory.module.edition.CommunityEditionModule; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; + +import static org.neo4j.kernel.impl.factory.DatabaseInfo.COMMUNITY; + +public class CommunityGraphFactory implements GraphFactory +{ + @Override + public GraphDatabaseFacade newGraphDatabase( Config config, Dependencies dependencies ) + { + File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); + GraphDatabaseFacadeFactory facadeFactory = new GraphDatabaseFacadeFactory( COMMUNITY, CommunityEditionModule::new ); + return facadeFactory.newFacade( storeDir, config, dependencies ); + } +} diff --git a/community/server/src/main/java/org/neo4j/server/database/Database.java b/community/server/src/main/java/org/neo4j/server/database/Database.java index 3949987710df5..f98f4d78c9a79 100644 --- a/community/server/src/main/java/org/neo4j/server/database/Database.java +++ b/community/server/src/main/java/org/neo4j/server/database/Database.java @@ -21,18 +21,11 @@ import java.io.File; -import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; -import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; import org.neo4j.kernel.lifecycle.Lifecycle; public interface Database extends Lifecycle { - interface Factory - { - Database newDatabase( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies ); - } - File getLocation(); GraphDatabaseFacade getGraph(); diff --git a/community/server/src/main/java/org/neo4j/server/database/GraphFactory.java b/community/server/src/main/java/org/neo4j/server/database/GraphFactory.java new file mode 100644 index 0000000000000..4e1bc1e86f40a --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/database/GraphFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.database; + +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; + +import static org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; + +@FunctionalInterface +public interface GraphFactory +{ + GraphDatabaseFacade newGraphDatabase( Config config, Dependencies dependencies ); +} diff --git a/community/server/src/main/java/org/neo4j/server/database/LifecycleManagingDatabase.java b/community/server/src/main/java/org/neo4j/server/database/LifecycleManagingDatabase.java index 9e8b3ce022eed..2886eaeb374c1 100644 --- a/community/server/src/main/java/org/neo4j/server/database/LifecycleManagingDatabase.java +++ b/community/server/src/main/java/org/neo4j/server/database/LifecycleManagingDatabase.java @@ -37,16 +37,6 @@ public class LifecycleManagingDatabase implements Database static final String CYPHER_WARMUP_QUERY = "MATCH (a:` This query is just used to load the cypher compiler during warmup. Please ignore `) RETURN a LIMIT 0"; - public interface GraphFactory - { - GraphDatabaseFacade newGraphDatabase( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies ); - } - - public static Database.Factory lifecycleManagingDatabase( final GraphFactory graphDbFactory ) - { - return ( config, dependencies ) -> new LifecycleManagingDatabase( config, graphDbFactory, dependencies ); - } - private final Config config; private final GraphFactory dbFactory; private final GraphDatabaseFacadeFactory.Dependencies dependencies; diff --git a/community/server/src/main/java/org/neo4j/server/exception/ServerStartupErrors.java b/community/server/src/main/java/org/neo4j/server/exception/ServerStartupErrors.java index c357df99d0367..1d22564efadde 100644 --- a/community/server/src/main/java/org/neo4j/server/exception/ServerStartupErrors.java +++ b/community/server/src/main/java/org/neo4j/server/exception/ServerStartupErrors.java @@ -19,8 +19,6 @@ */ package org.neo4j.server.exception; -import java.util.function.Function; - import org.neo4j.helpers.Exceptions; import org.neo4j.kernel.impl.storemigration.UpgradeNotAllowedException; import org.neo4j.server.ServerStartupException; @@ -37,35 +35,13 @@ private ServerStartupErrors() { } - /** - * Each function in this array handles translating one case. If it doesn't know how to translate a given - * throwable, it simply returns null. - */ - private static final Function[] translators = new Function[] { - // Handle upgrade errors - (Function) o -> - { - Throwable rootCause = Exceptions.rootCause( o ); - if ( rootCause instanceof UpgradeNotAllowedException ) - { - return new UpgradeDisallowedStartupException( (UpgradeNotAllowedException)rootCause ); - } - return null; - } - }; - public static ServerStartupException translateToServerStartupError( Throwable cause ) { - for ( Function translator : translators ) + Throwable rootCause = Exceptions.rootCause( cause ); + if ( rootCause instanceof UpgradeNotAllowedException ) { - ServerStartupException r = translator.apply( cause ); - if ( r != null ) - { - return r; - } + return new UpgradeDisallowedStartupException( (UpgradeNotAllowedException) rootCause ); } - return new ServerStartupException( format( "Starting Neo4j failed: %s", cause.getMessage() ), cause ); } - } diff --git a/community/server/src/main/java/org/neo4j/server/modules/RESTApiModule.java b/community/server/src/main/java/org/neo4j/server/modules/RESTApiModule.java index 5e37e8b985051..afe5c627b1c52 100644 --- a/community/server/src/main/java/org/neo4j/server/modules/RESTApiModule.java +++ b/community/server/src/main/java/org/neo4j/server/modules/RESTApiModule.java @@ -26,6 +26,7 @@ import org.neo4j.kernel.configuration.Config; import org.neo4j.logging.LogProvider; import org.neo4j.server.configuration.ServerSettings; +import org.neo4j.server.plugins.DefaultPluginManager; import org.neo4j.server.plugins.PluginManager; import org.neo4j.server.rest.web.BatchOperationService; import org.neo4j.server.rest.web.CollectUserAgentFilter; @@ -96,7 +97,6 @@ private List getClassNames() public void stop() { webServer.removeJAXRSClasses( getClassNames(), restApiUri().toString() ); - unloadPlugins(); } private URI restApiUri() @@ -106,12 +106,7 @@ private URI restApiUri() private void loadPlugins() { - plugins = new PluginManager( config, logProvider ); - } - - private void unloadPlugins() - { - // TODO + plugins = new DefaultPluginManager( logProvider ); } public PluginManager getPlugins() diff --git a/community/server/src/main/java/org/neo4j/server/plugins/DefaultPluginManager.java b/community/server/src/main/java/org/neo4j/server/plugins/DefaultPluginManager.java new file mode 100644 index 0000000000000..e17fd87c97c0e --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/plugins/DefaultPluginManager.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.plugins; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.neo4j.helpers.collection.Pair; +import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.logging.Log; +import org.neo4j.logging.LogProvider; +import org.neo4j.server.rest.repr.BadInputException; +import org.neo4j.server.rest.repr.ExtensionPointRepresentation; +import org.neo4j.server.rest.repr.Representation; + +public final class DefaultPluginManager implements PluginManager +{ + private final Map extensions = new HashMap<>(); + + public DefaultPluginManager( LogProvider logProvider ) + { + Map> extensions = new HashMap<>(); + Log log = logProvider.getLog( getClass() ); + Iterable loadedPlugins = ServerPlugin.load(); + for ( ServerPlugin plugin : loadedPlugins ) + { + PluginPointFactory factory = new PluginPointFactoryImpl(); + final ServerExtender extender = new ServerExtender( factory ); + try + { + plugin.loadServerExtender( extender ); + } + catch ( Exception | LinkageError ex ) + { + log.warn( "Failed to load plugin [%s]: %s", plugin.toString(), ex.getMessage() ); + continue; + } + Pair old = extensions.put( plugin.name, Pair.of( plugin, extender ) ); + if ( old != null ) + { + log.warn( String.format( "Extension naming conflict \"%s\" between \"%s\" and \"%s\"", plugin.name, + old.first().getClass(), plugin.getClass() ) ); + } + } + for ( Pair extension : extensions.values() ) + { + log.info( String.format( "Loaded server plugin \"%s\"", extension.first().name ) ); + for ( PluginPoint point : extension.other().all() ) + { + log.info( String.format( " %s.%s: %s", point.forType().getSimpleName(), point.name(), + point.getDescription() ) ); + } + this.extensions.put( extension.first().name, extension.other() ); + } + } + + @Override + public Map> getExensionsFor( Class type ) + { + Map> result = new HashMap<>(); + for ( Map.Entry extension : extensions.entrySet() ) + { + List methods = new ArrayList<>(); + for ( PluginPoint method : extension.getValue() + .getExtensionsFor( type ) ) + { + methods.add( method.name() ); + } + if ( !methods.isEmpty() ) + { + result.put( extension.getKey(), methods ); + } + } + return result; + } + + private PluginPoint extension( String name, Class type, String method ) throws PluginLookupException + { + ServerExtender extender = extensions.get( name ); + if ( extender == null ) + { + throw new PluginLookupException( "No such ServerPlugin: \"" + name + "\"" ); + } + return extender.getExtensionPoint( type, method ); + } + + @Override + public ExtensionPointRepresentation describe( String name, Class type, String method ) + throws PluginLookupException + { + return describe( extension( name, type, method ) ); + } + + private ExtensionPointRepresentation describe( PluginPoint extension ) + { + ExtensionPointRepresentation representation = new ExtensionPointRepresentation( extension.name(), + extension.forType(), extension.getDescription() ); + extension.describeParameters( representation ); + return representation; + } + + @Override + public List describeAll( String name ) throws PluginLookupException + { + ServerExtender extender = extensions.get( name ); + if ( extender == null ) + { + throw new PluginLookupException( "No such ServerPlugin: \"" + name + "\"" ); + } + List result = new ArrayList<>(); + for ( PluginPoint plugin : extender.all() ) + { + result.add( describe( plugin ) ); + } + return result; + } + + @Override + public Representation invoke( GraphDatabaseAPI graphDb, String name, Class type, String method, + T context, ParameterList params ) throws PluginLookupException, BadInputException, + PluginInvocationFailureException, BadPluginInvocationException + { + PluginPoint plugin = extension( name, type, method ); + try + { + return plugin.invoke( graphDb, context, params ); + } + catch ( BadInputException | PluginInvocationFailureException | BadPluginInvocationException e ) + { + throw e; + } + catch ( Exception e ) + { + throw new PluginInvocationFailureException( e ); + } + } + + @Override + public Set extensionNames() + { + return Collections.unmodifiableSet( extensions.keySet() ); + } +} diff --git a/community/server/src/main/java/org/neo4j/server/plugins/DisabledPluginManager.java b/community/server/src/main/java/org/neo4j/server/plugins/DisabledPluginManager.java new file mode 100644 index 0000000000000..aa55229ffec96 --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/plugins/DisabledPluginManager.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.plugins; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.neo4j.kernel.internal.GraphDatabaseAPI; +import org.neo4j.server.rest.repr.ExtensionPointRepresentation; +import org.neo4j.server.rest.repr.Representation; + +public class DisabledPluginManager implements PluginManager +{ + public static final PluginManager INSTANCE = new DisabledPluginManager(); + + private DisabledPluginManager() + { + } + + @Override + public Representation invoke( GraphDatabaseAPI graphDb, String name, Class type, String method, T context, ParameterList params ) + { + throw new UnsupportedOperationException(); + } + + @Override + public ExtensionPointRepresentation describe( String name, Class type, String method ) + { + throw new UnsupportedOperationException(); + } + + @Override + public List describeAll( String extensionName ) + { + return Collections.emptyList(); + } + + @Override + public Set extensionNames() + { + return Collections.emptySet(); + } + + @Override + public Map> getExensionsFor( Class type ) + { + return Collections.emptyMap(); + } +} diff --git a/community/server/src/main/java/org/neo4j/server/plugins/PluginManager.java b/community/server/src/main/java/org/neo4j/server/plugins/PluginManager.java index 47c41fb3761e1..edffa13ef48b8 100644 --- a/community/server/src/main/java/org/neo4j/server/plugins/PluginManager.java +++ b/community/server/src/main/java/org/neo4j/server/plugins/PluginManager.java @@ -19,152 +19,8 @@ */ package org.neo4j.server.plugins; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.neo4j.helpers.collection.Pair; -import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.internal.GraphDatabaseAPI; -import org.neo4j.logging.Log; -import org.neo4j.logging.LogProvider; -import org.neo4j.server.rest.repr.BadInputException; import org.neo4j.server.rest.repr.ExtensionInjector; -import org.neo4j.server.rest.repr.ExtensionPointRepresentation; -import org.neo4j.server.rest.repr.Representation; -public final class PluginManager implements ExtensionInjector, PluginInvocator +public interface PluginManager extends ExtensionInjector, PluginInvocator { - private final Map extensions = new HashMap<>(); - - public PluginManager( Config serverConfig, LogProvider logProvider ) - { - this( serverConfig, ServerPlugin.load(), logProvider ); - } - - PluginManager( Config serverConfig, Iterable plugins, LogProvider logProvider ) - { - Map> extensions = new HashMap<>(); - Log log = logProvider.getLog( getClass() ); - for ( ServerPlugin plugin : plugins ) - { - PluginPointFactory factory = new PluginPointFactoryImpl(); - final ServerExtender extender = new ServerExtender( factory ); - try - { - plugin.loadServerExtender( extender ); - } - catch ( Exception | LinkageError ex ) - { - log.warn( "Failed to load plugin [%s]: %s", plugin.toString(), ex.getMessage() ); - continue; - } - Pair old = extensions.put( plugin.name, Pair.of( plugin, extender ) ); - if ( old != null ) - { - log.warn( String.format( "Extension naming conflict \"%s\" between \"%s\" and \"%s\"", plugin.name, - old.first().getClass(), plugin.getClass() ) ); - } - } - for ( Pair extension : extensions.values() ) - { - log.info( String.format( "Loaded server plugin \"%s\"", extension.first().name ) ); - for ( PluginPoint point : extension.other().all() ) - { - log.info( String.format( " %s.%s: %s", point.forType().getSimpleName(), point.name(), - point.getDescription() ) ); - } - this.extensions.put( extension.first().name, extension.other() ); - } - } - - @Override - public Map> getExensionsFor( Class type ) - { - Map> result = new HashMap<>(); - for ( Map.Entry extension : extensions.entrySet() ) - { - List methods = new ArrayList<>(); - for ( PluginPoint method : extension.getValue() - .getExtensionsFor( type ) ) - { - methods.add( method.name() ); - } - if ( !methods.isEmpty() ) - { - result.put( extension.getKey(), methods ); - } - } - return result; - } - - private PluginPoint extension( String name, Class type, String method ) throws PluginLookupException - { - ServerExtender extender = extensions.get( name ); - if ( extender == null ) - { - throw new PluginLookupException( "No such ServerPlugin: \"" + name + "\"" ); - } - return extender.getExtensionPoint( type, method ); - } - - @Override - public ExtensionPointRepresentation describe( String name, Class type, String method ) - throws PluginLookupException - { - return describe( extension( name, type, method ) ); - } - - private ExtensionPointRepresentation describe( PluginPoint extension ) - { - ExtensionPointRepresentation representation = new ExtensionPointRepresentation( extension.name(), - extension.forType(), extension.getDescription() ); - extension.describeParameters( representation ); - return representation; - } - - @Override - public List describeAll( String name ) throws PluginLookupException - { - ServerExtender extender = extensions.get( name ); - if ( extender == null ) - { - throw new PluginLookupException( "No such ServerPlugin: \"" + name + "\"" ); - } - List result = new ArrayList<>(); - for ( PluginPoint plugin : extender.all() ) - { - result.add( describe( plugin ) ); - } - return result; - } - - @Override - public Representation invoke( GraphDatabaseAPI graphDb, String name, Class type, String method, - T context, ParameterList params ) throws PluginLookupException, BadInputException, - PluginInvocationFailureException, BadPluginInvocationException - { - PluginPoint plugin = extension( name, type, method ); - try - { - return plugin.invoke( graphDb, context, params ); - } - catch ( BadInputException | PluginInvocationFailureException | BadPluginInvocationException e ) - { - throw e; - } - catch ( Exception e ) - { - throw new PluginInvocationFailureException( e ); - } - } - - @Override - public Set extensionNames() - { - return Collections.unmodifiableSet( extensions.keySet() ); - } } diff --git a/community/server/src/main/java/org/neo4j/server/rest/transactional/DisabledTransactionRegistry.java b/community/server/src/main/java/org/neo4j/server/rest/transactional/DisabledTransactionRegistry.java new file mode 100644 index 0000000000000..550216482d8dc --- /dev/null +++ b/community/server/src/main/java/org/neo4j/server/rest/transactional/DisabledTransactionRegistry.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.rest.transactional; + +public class DisabledTransactionRegistry implements TransactionRegistry +{ + public static final TransactionRegistry INSTANCE = new DisabledTransactionRegistry(); + + private DisabledTransactionRegistry() + { + } + + @Override + public long begin( TransactionHandle handle ) + { + throw new UnsupportedOperationException(); + } + + @Override + public long release( long id, TransactionHandle transactionHandle ) + { + throw new UnsupportedOperationException(); + } + + @Override + public TransactionHandle acquire( long id ) + { + throw new UnsupportedOperationException(); + } + + @Override + public void forget( long id ) + { + } + + @Override + public TransactionHandle terminate( long id ) + { + throw new UnsupportedOperationException(); + } + + @Override + public void rollbackAllSuspendedTransactions() + { + } +} diff --git a/community/server/src/main/java/org/neo4j/server/web/Jetty9WebServer.java b/community/server/src/main/java/org/neo4j/server/web/Jetty9WebServer.java index e3e4dd9e0f318..78a02f06040f9 100644 --- a/community/server/src/main/java/org/neo4j/server/web/Jetty9WebServer.java +++ b/community/server/src/main/java/org/neo4j/server/web/Jetty9WebServer.java @@ -48,11 +48,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; +import java.util.Objects; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.BlockingQueue; import java.util.function.Consumer; +import java.util.stream.Stream; import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.ServletException; @@ -71,11 +72,10 @@ import org.neo4j.ssl.SslPolicy; import static java.lang.String.format; +import static java.util.stream.Collectors.joining; /** * This class handles the configuration and runtime management of a Jetty web server. The server is restartable. - * - * TODO: it really should be split up into a builder that returns a Closeable, to separate between the conf and runtime part. */ public class Jetty9WebServer implements WebServer { @@ -90,11 +90,11 @@ public class Jetty9WebServer implements WebServer private Server jetty; private HandlerCollection handlers; - private ListenSocketAddress jettyAddress = DEFAULT_ADDRESS; - private Optional jettyHttpsAddress = Optional.empty(); + private ListenSocketAddress httpAddress = DEFAULT_ADDRESS; + private ListenSocketAddress httpsAddress; - private ServerConnector serverConnector; - private ServerConnector secureServerConnector; + private ServerConnector httpConnector; + private ServerConnector httpsConnector; private final HashMap staticContent = new HashMap<>(); private final Map jaxRSPackages = new HashMap<>(); @@ -119,21 +119,26 @@ public void start() throws Exception { if ( jetty == null ) { - JettyThreadCalculator jettyThreadCalculator = new JettyThreadCalculator( jettyMaxThreads ); + verifyAddressConfiguration(); + JettyThreadCalculator jettyThreadCalculator = new JettyThreadCalculator( jettyMaxThreads ); jetty = new Server( createQueuedThreadPool( jettyThreadCalculator ) ); - serverConnector = connectorFactory.createConnector( jetty, jettyAddress, jettyThreadCalculator ); - jetty.addConnector( serverConnector ); - jettyHttpsAddress.ifPresent( address -> + if ( httpAddress != null ) + { + httpConnector = connectorFactory.createConnector( jetty, httpAddress, jettyThreadCalculator ); + jetty.addConnector( httpConnector ); + } + + if ( httpsAddress != null ) { if ( sslPolicy == null ) { throw new RuntimeException( "HTTPS set to enabled, but no SSL policy provided" ); } - secureServerConnector = sslSocketFactory.createConnector( jetty, sslPolicy, address, jettyThreadCalculator ); - jetty.addConnector( secureServerConnector ); - } ); + httpsConnector = sslSocketFactory.createConnector( jetty, sslPolicy, httpsAddress, jettyThreadCalculator ); + jetty.addConnector( httpsConnector ); + } if ( jettyCreatedCallback != null ) { @@ -189,9 +194,21 @@ public void stop() } @Override - public void setAddress( ListenSocketAddress address ) + public void setHttpAddress( ListenSocketAddress address ) { - jettyAddress = address; + httpAddress = address; + } + + @Override + public void setHttpsAddress( ListenSocketAddress address ) + { + httpsAddress = address; + } + + @Override + public void setSslPolicy( SslPolicy policy ) + { + sslPolicy = policy; } @Override @@ -301,24 +318,12 @@ public void setRequestLog( RequestLog requestLog ) this.requestLog = requestLog; } - @Override - public void setHttpsAddress( Optional address ) - { - jettyHttpsAddress = address; - } - - @Override - public void setSslPolicy( SslPolicy sslPolicy ) - { - this.sslPolicy = sslPolicy; - } - public Server getJetty() { return jetty; } - protected void startJetty() throws Exception + private void startJetty() throws Exception { try { @@ -326,29 +331,20 @@ protected void startJetty() throws Exception } catch ( BindException e ) { - if ( jettyHttpsAddress.isPresent() ) - { - throw new PortBindException( jettyAddress, jettyHttpsAddress.get(), e ); - } - else - { - throw new PortBindException( jettyAddress, e ); - } + throw new PortBindException( httpAddress, httpsAddress, e ); } } @Override public InetSocketAddress getLocalHttpAddress() { - return toSocketAddress( serverConnector ); + return getAddress( "HTTP", httpConnector ); } @Override public InetSocketAddress getLocalHttpsAddress() { - return Optional.ofNullable( secureServerConnector) - .map( Jetty9WebServer::toSocketAddress ) - .orElseThrow( () -> new IllegalStateException( "Secure connector is not configured" ) ); + return getAddress( "HTTPS", httpsConnector ); } private void loadAllMounts() @@ -474,8 +470,8 @@ private void loadStaticContent( String mountPoint ) } else { - log.warn( "No static content available for Neo Server at %s, management console may not be available.", - jettyAddress ); + log.warn( "No static content available for Neo4j Server at %s. management console may not be available.", + addressConfigurationDescription() ); } } catch ( Exception e ) @@ -522,11 +518,31 @@ private void addFiltersTo( ServletContextHandler context ) } } - private static InetSocketAddress toSocketAddress( ServerConnector connector ) + private static InetSocketAddress getAddress( String name, ServerConnector connector ) { + if ( connector == null ) + { + throw new IllegalStateException( name + " connector is not configured" ); + } return new InetSocketAddress( connector.getHost(), connector.getLocalPort() ); } + private void verifyAddressConfiguration() + { + if ( httpAddress == null && httpsAddress == null ) + { + throw new IllegalStateException( "Either HTTP or HTTPS address must be configured to run the server" ); + } + } + + private String addressConfigurationDescription() + { + return Stream.of( httpAddress, httpsAddress ) + .filter( Objects::nonNull ) + .map( Object::toString ) + .collect( joining( ", " ) ); + } + private static class FilterDefinition { private final Filter filter; diff --git a/community/server/src/main/java/org/neo4j/server/web/WebServer.java b/community/server/src/main/java/org/neo4j/server/web/WebServer.java index 55983230c37b6..657008962dad5 100644 --- a/community/server/src/main/java/org/neo4j/server/web/WebServer.java +++ b/community/server/src/main/java/org/neo4j/server/web/WebServer.java @@ -26,7 +26,6 @@ import java.net.InetSocketAddress; import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.function.Consumer; import javax.servlet.Filter; import javax.servlet.ServletException; @@ -40,9 +39,9 @@ public interface WebServer { - void setAddress( ListenSocketAddress address ); + void setHttpAddress( ListenSocketAddress address ); - void setHttpsAddress( Optional address ); + void setHttpsAddress( ListenSocketAddress address ); void setSslPolicy( SslPolicy sslPolicy ); diff --git a/community/server/src/test/java/org/neo4j/server/BaseBootstrapperTestIT.java b/community/server/src/test/java/org/neo4j/server/BaseBootstrapperIT.java similarity index 53% rename from community/server/src/test/java/org/neo4j/server/BaseBootstrapperTestIT.java rename to community/server/src/test/java/org/neo4j/server/BaseBootstrapperIT.java index 19a6bf6afc4be..7e2f6f16ce280 100644 --- a/community/server/src/test/java/org/neo4j/server/BaseBootstrapperTestIT.java +++ b/community/server/src/test/java/org/neo4j/server/BaseBootstrapperIT.java @@ -26,28 +26,41 @@ import org.junit.rules.TemporaryFolder; import java.io.File; +import java.net.Socket; import java.util.Map; import java.util.concurrent.TimeUnit; +import org.neo4j.graphdb.Label; +import org.neo4j.graphdb.Node; +import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.config.Setting; +import org.neo4j.helpers.HostnamePort; import org.neo4j.kernel.configuration.BoltConnector; import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.configuration.ConnectorPortRegister; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; +import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.neo4j.ports.allocation.PortAuthority; import org.neo4j.test.server.ExclusiveServerTestBase; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.neo4j.bolt.v1.transport.integration.Neo4jWithSocket.DEFAULT_CONNECTOR_KEY; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.data_directory; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.forced_kernel_id; import static org.neo4j.graphdb.factory.GraphDatabaseSettings.logs_directory; +import static org.neo4j.helpers.collection.Iterators.single; import static org.neo4j.helpers.collection.MapUtil.store; import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.test.assertion.Assert.assertEventually; -public abstract class BaseBootstrapperTestIT extends ExclusiveServerTestBase +public abstract class BaseBootstrapperIT extends ExclusiveServerTestBase { @Rule public TemporaryFolder tempDir = new TemporaryFolder(); @@ -101,7 +114,7 @@ public void canSpecifyConfigFile() throws Throwable // Given File configFile = tempDir.newFile( Config.DEFAULT_CONFIG_FILE_NAME ); - Map properties = stringMap( forced_kernel_id.name(), "ourcustomvalue" ); + Map properties = stringMap( forced_kernel_id.name(), "ourcustomvalue" ); properties.putAll( ServerTestUtils.getDefaultRelativeProperties() ); properties.put( "dbms.connector.http.type", "HTTP" ); properties.put( "dbms.connector.http.enabled", "true" ); @@ -123,9 +136,9 @@ public void canSpecifyConfigFile() throws Throwable public void canOverrideConfigValues() throws Throwable { // Given - File configFile = tempDir.newFile( Config.DEFAULT_CONFIG_FILE_NAME); + File configFile = tempDir.newFile( Config.DEFAULT_CONFIG_FILE_NAME ); - Map properties = stringMap( forced_kernel_id.name(), "thisshouldnotshowup" ); + Map properties = stringMap( forced_kernel_id.name(), "thisshouldnotshowup" ); properties.putAll( ServerTestUtils.getDefaultRelativeProperties() ); properties.put( "dbms.connector.http.type", "HTTP" ); properties.put( "dbms.connector.http.enabled", "true" ); @@ -144,8 +157,141 @@ public void canOverrideConfigValues() throws Throwable assertThat( bootstrapper.getServer().getConfig().get( forced_kernel_id ), equalTo( "mycustomvalue" ) ); } + @Test + public void shouldStartWithHttpHttpsAndBoltDisabled() throws Exception + { + testStartupWithConnectors( false, false, false ); + } + + @Test + public void shouldStartWithHttpEnabledAndHttpsBoltDisabled() throws Exception + { + testStartupWithConnectors( true, false, false ); + } + + @Test + public void shouldStartWithHttpsEnabledAndHttpBoltDisabled() throws Exception + { + testStartupWithConnectors( false, true, false ); + } + + @Test + public void shouldStartWithBoltEnabledAndHttpHttpsDisabled() throws Exception + { + testStartupWithConnectors( false, false, true ); + } + + @Test + public void shouldStartWithHttpHttpsEnabledAndBoltDisabled() throws Exception + { + testStartupWithConnectors( true, true, false ); + } + + @Test + public void shouldStartWithHttpBoltEnabledAndHttpsDisabled() throws Exception + { + testStartupWithConnectors( true, false, true ); + } + + @Test + public void shouldStartWithHttpsBoltEnabledAndHttpDisabled() throws Exception + { + testStartupWithConnectors( false, true, true ); + } + + private void testStartupWithConnectors( boolean httpEnabled, boolean httpsEnabled, boolean boltEnabled ) throws Exception + { + int httpPort = httpEnabled ? 0 : 7474; + int httpsPort = httpsEnabled ? 0 : 7473; + int boltPort = boltEnabled ? 0 : 7687; + + int resultCode = ServerBootstrapper.start( bootstrapper, + "--home-dir", tempDir.newFolder( "home-dir" ).getAbsolutePath(), + "-c", configOption( data_directory, tempDir.getRoot().getAbsolutePath() ), + "-c", configOption( logs_directory, tempDir.getRoot().getAbsolutePath() ), + + "-c", "dbms.connector.http.enabled=" + httpEnabled, + "-c", "dbms.connector.http.listen_address=:" + httpPort, + + "-c", "dbms.connector.https.enabled=" + httpsEnabled, + "-c", "dbms.connector.https.listen_address=:" + httpsPort, + + "-c", "dbms.connector.bolt.enabled=" + boltEnabled, + "-c", "dbms.connector.bolt.listen_address=:" + boltPort + ); + + assertEquals( ServerBootstrapper.OK, resultCode ); + assertEventually( "Server was not started", bootstrapper::isRunning, is( true ), 1, TimeUnit.MINUTES ); + assertDbAccessibleAsEmbedded(); + + verifyConnector( "http", 7474, httpEnabled ); + verifyConnector( "https", 7473, httpsEnabled ); + verifyConnector( "bolt", 7687, boltEnabled ); + } + protected String configOption( Setting setting, String value ) { return setting.name() + "=" + value; } + + private void assertDbAccessibleAsEmbedded() + { + GraphDatabaseAPI db = db(); + + Label label = () -> "Node"; + String propertyKey = "key"; + String propertyValue = "value"; + + try ( Transaction tx = db.beginTx() ) + { + db.createNode( label ).setProperty( propertyKey, propertyValue ); + tx.success(); + } + try ( Transaction tx = db.beginTx() ) + { + Node node = single( db.findNodes( label ) ); + assertEquals( propertyValue, node.getProperty( propertyKey ) ); + tx.success(); + } + } + + private void verifyConnector( String name, int defaultPort, boolean enabled ) + { + HostnamePort address = connectorAddress( name ); + if ( enabled ) + { + assertNotNull( address ); + assertTrue( canConnectToSocket( address.getHost(), address.getPort() ) ); + } + else + { + assertNull( address ); + assertFalse( canConnectToSocket( "localhost", defaultPort ) ); + } + } + + private HostnamePort connectorAddress( String name ) + { + ConnectorPortRegister portRegister = db().getDependencyResolver().resolveDependency( ConnectorPortRegister.class ); + return portRegister.getLocalAddress( name ); + + } + + private GraphDatabaseFacade db() + { + return bootstrapper.getServer().getDatabase().getGraph(); + } + + private static boolean canConnectToSocket( String host, int port ) + { + try + { + new Socket( host, port ).close(); + return true; + } + catch ( Throwable ignore ) + { + return false; + } + } } diff --git a/community/server/src/test/java/org/neo4j/server/CommunityBootstrapperTestIT.java b/community/server/src/test/java/org/neo4j/server/CommunityBootstrapperIT.java similarity index 92% rename from community/server/src/test/java/org/neo4j/server/CommunityBootstrapperTestIT.java rename to community/server/src/test/java/org/neo4j/server/CommunityBootstrapperIT.java index ebb461b40ff87..84214489e4683 100644 --- a/community/server/src/test/java/org/neo4j/server/CommunityBootstrapperTestIT.java +++ b/community/server/src/test/java/org/neo4j/server/CommunityBootstrapperIT.java @@ -19,7 +19,7 @@ */ package org.neo4j.server; -public class CommunityBootstrapperTestIT extends BaseBootstrapperTestIT +public class CommunityBootstrapperIT extends BaseBootstrapperIT { @Override protected ServerBootstrapper newBootstrapper() diff --git a/community/server/src/test/java/org/neo4j/server/HttpsAccessIT.java b/community/server/src/test/java/org/neo4j/server/HttpsAccessIT.java index dba56f62c8930..e88383a2f097c 100644 --- a/community/server/src/test/java/org/neo4j/server/HttpsAccessIT.java +++ b/community/server/src/test/java/org/neo4j/server/HttpsAccessIT.java @@ -19,24 +19,30 @@ */ package org.neo4j.server; +import org.apache.http.client.utils.URIBuilder; import org.junit.After; import org.junit.Before; import org.junit.Test; -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; +import java.net.URI; import java.security.SecureRandom; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; +import org.neo4j.graphdb.DependencyResolver; +import org.neo4j.helpers.HostnamePort; +import org.neo4j.kernel.configuration.ConnectorPortRegister; +import org.neo4j.server.helpers.CommunityServerBuilder; import org.neo4j.test.server.ExclusiveServerTestBase; import org.neo4j.test.server.HTTP; import org.neo4j.test.server.InsecureTrustManager; import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.neo4j.server.helpers.CommunityServerBuilder.serverOnRandomPorts; import static org.neo4j.test.server.HTTP.GET; @@ -45,20 +51,88 @@ public class HttpsAccessIT extends ExclusiveServerTestBase { + private SSLSocketFactory originalSslSocketFactory; private CommunityNeoServer server; + @Before + public void setUp() + { + originalSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); + } + @After - public void stopTheServer() + public void tearDown() { + HttpsURLConnection.setDefaultSSLSocketFactory( originalSslSocketFactory ); server.stop(); } - @Before - public void startServer() throws NoSuchAlgorithmException, KeyManagementException, IOException + @Test + public void serverShouldSupportSsl() throws Exception + { + startServer(); + + assertThat( GET( httpsUri() ).status(), is( 200 ) ); + assertThat( GET(server.baseUri().toString()).status(), is( 200 ) ); + } + + @Test + public void txEndpointShouldReplyWithHttpsWhenItReturnsURLs() throws Exception { - server = serverOnRandomPorts().withHttpsEnabled() - .usingDataDir( folder.directory( name.getMethodName() ).getAbsolutePath() ) - .build(); + startServer(); + + String baseUri = server.baseUri().toString(); + HTTP.Response response = POST( baseUri + "db/data/transaction", quotedJson( "{'statements':[]}" ) ); + + assertThat( response.location(), startsWith( baseUri ) ); + assertThat( response.get( "commit" ).asText(), startsWith( baseUri ) ); + } + + @Test + public void shouldExposeBaseUriWhenHttpEnabledAndHttpsDisabled() throws Exception + { + startServer( true, false ); + + URI uri = server.baseUri(); + + assertEquals( "http", uri.getScheme() ); + HostnamePort expectedHostPort = addressForConnector( "http" ); + assertEquals( expectedHostPort.getHost(), uri.getHost() ); + assertEquals( expectedHostPort.getPort(), uri.getPort() ); + } + + @Test + public void shouldExposeBaseUriWhenHttpDisabledAndHttpsEnabled() throws Exception + { + startServer( false, true ); + + URI uri = server.baseUri(); + + assertEquals( "https", uri.getScheme() ); + HostnamePort expectedHostPort = addressForConnector( "https" ); + assertEquals( expectedHostPort.getHost(), uri.getHost() ); + assertEquals( expectedHostPort.getPort(), uri.getPort() ); + } + + private void startServer() throws Exception + { + startServer( true, true ); + } + + private void startServer( boolean httpEnabled, boolean httpsEnabled ) throws Exception + { + CommunityServerBuilder serverBuilder = serverOnRandomPorts().usingDataDir( folder.directory( name.getMethodName() ).getAbsolutePath() ); + if ( !httpEnabled ) + { + serverBuilder.withHttpDisabled(); + } + if ( httpsEnabled ) + { + serverBuilder.withHttpsEnabled(); + } + + server = serverBuilder.build(); + server.start(); // Because we are generating a non-CA-signed certificate, we need to turn off verification in the client. // This is ironic, since there is no proper verification on the CA side in the first place, but I digress. @@ -70,29 +144,23 @@ public void startServer() throws NoSuchAlgorithmException, KeyManagementExceptio HttpsURLConnection.setDefaultSSLSocketFactory( sc.getSocketFactory() ); } - @Test - public void serverShouldSupportSsl() + private String httpsUri() throws Exception { - // When - server.start(); + HostnamePort hostPort = addressForConnector( "https" ); + assertNotNull( hostPort ); - // Then - assertThat( server.httpsIsEnabled(), is( true ) ); - assertThat( GET(server.baseUri().toString()).status(), is( 200 ) ); + return new URIBuilder() + .setScheme( "https" ) + .setHost( hostPort.getHost() ) + .setPort( hostPort.getPort() ) + .build() + .toString(); } - @Test - public void txEndpointShouldReplyWithHttpsWhenItReturnsURLs() throws Exception + private HostnamePort addressForConnector( String name ) { - // Given - server.start(); - - // When - String baseUri = server.baseUri().toString(); - HTTP.Response response = POST( baseUri + "db/data/transaction", quotedJson( "{'statements':[]}" ) ); - - // Then - assertThat( response.location(), startsWith( baseUri ) ); - assertThat( response.get( "commit" ).asText(), startsWith( baseUri ) ); + DependencyResolver resolver = server.database.getGraph().getDependencyResolver(); + ConnectorPortRegister portRegister = resolver.resolveDependency( ConnectorPortRegister.class ); + return portRegister.getLocalAddress( name ); } } diff --git a/community/server/src/test/java/org/neo4j/server/ServerBootstrapperTest.java b/community/server/src/test/java/org/neo4j/server/ServerBootstrapperTest.java index ea2400dfeea8a..65ee0d12efa37 100644 --- a/community/server/src/test/java/org/neo4j/server/ServerBootstrapperTest.java +++ b/community/server/src/test/java/org/neo4j/server/ServerBootstrapperTest.java @@ -24,16 +24,14 @@ import java.io.File; import java.nio.file.Files; -import java.util.Collection; -import java.util.Collections; import java.util.Optional; -import javax.annotation.Nonnull; import org.neo4j.graphdb.facade.GraphDatabaseDependencies; import org.neo4j.helpers.collection.MapUtil; import org.neo4j.kernel.configuration.Config; -import org.neo4j.kernel.configuration.ConfigurationValidator; import org.neo4j.logging.LogProvider; +import org.neo4j.server.database.CommunityGraphFactory; +import org.neo4j.server.database.GraphFactory; import org.neo4j.test.rule.SuppressOutput; import org.neo4j.test.rule.TestDirectory; @@ -58,17 +56,16 @@ public void shouldNotThrowNullPointerExceptionIfConfigurationValidationFails() t ServerBootstrapper serverBootstrapper = new ServerBootstrapper() { @Override - protected NeoServer createNeoServer( Config config, GraphDatabaseDependencies dependencies, - LogProvider userLogProvider ) + protected GraphFactory createGraphFactory( Config config ) { - return mock( NeoServer.class ); + return new CommunityGraphFactory(); } - @Nonnull @Override - protected Collection configurationValidators() + protected NeoServer createNeoServer( GraphFactory graphFactory, Config config, GraphDatabaseDependencies dependencies, + LogProvider userLogProvider ) { - return Collections.emptyList(); + return mock( NeoServer.class ); } }; diff --git a/community/server/src/test/java/org/neo4j/server/database/InMemoryGraphFactory.java b/community/server/src/test/java/org/neo4j/server/database/InMemoryGraphFactory.java new file mode 100644 index 0000000000000..bb441c3efe1a7 --- /dev/null +++ b/community/server/src/test/java/org/neo4j/server/database/InMemoryGraphFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.database; + +import java.io.File; + +import org.neo4j.graphdb.facade.GraphDatabaseDependencies; +import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.kernel.configuration.BoltConnector; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; +import org.neo4j.test.ImpermanentGraphDatabase; + +import static org.neo4j.helpers.collection.MapUtil.stringMap; + +public class InMemoryGraphFactory implements GraphFactory +{ + @Override + public GraphDatabaseFacade newGraphDatabase( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies ) + { + File storeDir = config.get( GraphDatabaseSettings.database_path ); + config.augment( stringMap( GraphDatabaseSettings.ephemeral.name(), "true", + new BoltConnector( "bolt" ).listen_address.name(), "localhost:0" ) ); + return new ImpermanentGraphDatabase( storeDir, config, GraphDatabaseDependencies.newDependencies( dependencies ) ); + } +} diff --git a/community/server/src/test/java/org/neo4j/server/database/LifecycleManagingDatabaseTest.java b/community/server/src/test/java/org/neo4j/server/database/LifecycleManagingDatabaseTest.java index 7e6170a99c1f9..83f350f8d5354 100644 --- a/community/server/src/test/java/org/neo4j/server/database/LifecycleManagingDatabaseTest.java +++ b/community/server/src/test/java/org/neo4j/server/database/LifecycleManagingDatabaseTest.java @@ -42,7 +42,7 @@ public void mustIgnoreExceptionsFromPreLoadingCypherQuery() Config config = Config.defaults(); GraphDatabaseFacadeFactory.Dependencies deps = GraphDatabaseDependencies.newDependencies().userLogProvider( NullLogProvider.getInstance() ); - LifecycleManagingDatabase.GraphFactory factory = ( conf, dependencies ) -> mockDb; + GraphFactory factory = new SimpleGraphFactory( mockDb ); LifecycleManagingDatabase db = new LifecycleManagingDatabase( config, factory, deps ) { @Override diff --git a/community/server/src/test/java/org/neo4j/server/database/SimpleGraphFactory.java b/community/server/src/test/java/org/neo4j/server/database/SimpleGraphFactory.java new file mode 100644 index 0000000000000..7396f21adab85 --- /dev/null +++ b/community/server/src/test/java/org/neo4j/server/database/SimpleGraphFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.server.database; + +import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; + +public class SimpleGraphFactory implements GraphFactory +{ + private final GraphDatabaseFacade db; + + public SimpleGraphFactory( GraphDatabaseFacade db ) + { + this.db = db; + } + + @Override + public GraphDatabaseFacade newGraphDatabase( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies ) + { + return db; + } +} diff --git a/community/server/src/test/java/org/neo4j/server/database/TestLifecycleManagedDatabase.java b/community/server/src/test/java/org/neo4j/server/database/TestLifecycleManagedDatabase.java index c007aca94195f..49190888574ac 100644 --- a/community/server/src/test/java/org/neo4j/server/database/TestLifecycleManagedDatabase.java +++ b/community/server/src/test/java/org/neo4j/server/database/TestLifecycleManagedDatabase.java @@ -57,7 +57,7 @@ public class TestLifecycleManagedDatabase private File dataDirectory; private Database theDatabase; private boolean deletionFailureOk; - private LifecycleManagingDatabase.GraphFactory dbFactory; + private GraphFactory dbFactory; private Config dbConfig; @Before @@ -65,7 +65,7 @@ public void setup() throws Exception { dataDirectory = createTempDir(); - dbFactory = createGraphFactory(); + dbFactory = new SimpleGraphFactory( (GraphDatabaseFacade) dbRule.getGraphDatabaseAPI() ); dbConfig = Config.defaults( GraphDatabaseSettings.data_directory, dataDirectory.getAbsolutePath() ); theDatabase = newDatabase(); } @@ -144,9 +144,4 @@ public void shouldBeAbleToGetLocation() throws Throwable assertThat( theDatabase.getLocation().getAbsolutePath(), is( dbConfig.get( GraphDatabaseSettings.database_path ).getAbsolutePath() ) ); } - - private LifecycleManagingDatabase.GraphFactory createGraphFactory() - { - return ( config, dependencies ) -> (GraphDatabaseFacade) dbRule.getGraphDatabaseAPI(); - } } diff --git a/community/server/src/test/java/org/neo4j/server/helpers/CommunityServerBuilder.java b/community/server/src/test/java/org/neo4j/server/helpers/CommunityServerBuilder.java index 0d2e014bbba7e..24c4505ea3190 100644 --- a/community/server/src/test/java/org/neo4j/server/helpers/CommunityServerBuilder.java +++ b/community/server/src/test/java/org/neo4j/server/helpers/CommunityServerBuilder.java @@ -31,7 +31,6 @@ import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.helpers.ListenSocketAddress; -import org.neo4j.kernel.configuration.BoltConnector; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.HttpConnector; import org.neo4j.kernel.configuration.HttpConnector.Encryption; @@ -43,15 +42,14 @@ import org.neo4j.server.CommunityNeoServer; import org.neo4j.server.ServerTestUtils; import org.neo4j.server.configuration.ServerSettings; +import org.neo4j.server.database.CommunityGraphFactory; import org.neo4j.server.database.Database; -import org.neo4j.server.database.LifecycleManagingDatabase; +import org.neo4j.server.database.InMemoryGraphFactory; import org.neo4j.server.preflight.PreFlightTasks; import org.neo4j.server.rest.web.DatabaseActions; -import org.neo4j.test.ImpermanentGraphDatabase; import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.server.ServerTestUtils.asOneLine; -import static org.neo4j.server.database.LifecycleManagingDatabase.lifecycleManagingDatabase; public class CommunityServerBuilder { @@ -73,19 +71,11 @@ public class CommunityServerBuilder System.setProperty( "sun.net.http.allowRestrictedHeaders", "true" ); } - private static LifecycleManagingDatabase.GraphFactory IN_MEMORY_DB = ( config, dependencies ) -> - { - File storeDir = config.get( GraphDatabaseSettings.database_path ); - config.augment( stringMap( GraphDatabaseSettings.ephemeral.name(), "true", - new BoltConnector( "bolt" ).listen_address.name(), "localhost:0" ) ); - return new ImpermanentGraphDatabase( storeDir, config, - GraphDatabaseDependencies.newDependencies( dependencies ) ); - }; - private String[] autoIndexedNodeKeys; private final String[] autoIndexedRelationshipKeys = null; private String[] securityRuleClassNames; private boolean persistent; + private boolean httpEnabled = true; private boolean httpsEnabled; public static CommunityServerBuilder server( LogProvider logProvider ) @@ -181,7 +171,7 @@ public Map createConfiguration( File temporaryFolder ) HttpConnector httpsConnector = new HttpConnector( "https", Encryption.TLS ); properties.put( httpConnector.type.name(), "HTTP" ); - properties.put( httpConnector.enabled.name(), "true" ); + properties.put( httpConnector.enabled.name(), String.valueOf( httpEnabled ) ); properties.put( httpConnector.address.name(), address.toString() ); properties.put( httpConnector.encryption.name(), "NONE" ); @@ -319,6 +309,12 @@ public CommunityServerBuilder withHttpsEnabled() return this; } + public CommunityServerBuilder withHttpDisabled() + { + httpEnabled = false; + return this; + } + public CommunityServerBuilder withProperty( String key, String value ) { arbitraryProperties.put( key, value ); @@ -352,11 +348,9 @@ private class TestCommunityNeoServer extends CommunityNeoServer { private final File configFile; - private TestCommunityNeoServer( Config config, File configFile, GraphDatabaseFacadeFactory - .Dependencies dependencies, LogProvider logProvider ) + private TestCommunityNeoServer( Config config, File configFile, GraphDatabaseFacadeFactory.Dependencies dependencies, LogProvider logProvider ) { - super( config, lifecycleManagingDatabase( persistent ? COMMUNITY_FACTORY : IN_MEMORY_DB ), dependencies, - logProvider ); + super( config, persistent ? new CommunityGraphFactory() : new InMemoryGraphFactory(), dependencies, logProvider ); this.configFile = configFile; } diff --git a/community/server/src/test/java/org/neo4j/server/web/Jetty9WebServerIT.java b/community/server/src/test/java/org/neo4j/server/web/Jetty9WebServerIT.java index c476b92cd0ef8..b5a3f005129be 100644 --- a/community/server/src/test/java/org/neo4j/server/web/Jetty9WebServerIT.java +++ b/community/server/src/test/java/org/neo4j/server/web/Jetty9WebServerIT.java @@ -48,7 +48,7 @@ public void shouldBeAbleToUsePortZero() throws Exception // Given webServer = new Jetty9WebServer( NullLogProvider.getInstance(), Config.defaults(), NetworkConnectionTracker.NO_OP ); - webServer.setAddress( new ListenSocketAddress( "localhost", 0 ) ); + webServer.setHttpAddress( new ListenSocketAddress( "localhost", 0 ) ); // When webServer.start(); @@ -61,7 +61,7 @@ public void shouldBeAbleToRestart() throws Throwable { // given webServer = new Jetty9WebServer( NullLogProvider.getInstance(), Config.defaults(), NetworkConnectionTracker.NO_OP ); - webServer.setAddress( new ListenSocketAddress( "127.0.0.1", 7878 ) ); + webServer.setHttpAddress( new ListenSocketAddress( "127.0.0.1", 7878 ) ); // when webServer.start(); diff --git a/community/server/src/test/java/org/neo4j/server/web/JettyThreadLimitIT.java b/community/server/src/test/java/org/neo4j/server/web/JettyThreadLimitIT.java index 452e044eeddcf..53c7eed55e6f5 100644 --- a/community/server/src/test/java/org/neo4j/server/web/JettyThreadLimitIT.java +++ b/community/server/src/test/java/org/neo4j/server/web/JettyThreadLimitIT.java @@ -50,7 +50,7 @@ public void shouldHaveConfigurableJettyThreadPoolSize() throws Exception int selectorThreads = 1; // ... and 1 thread will become a selector... int jobThreads = configuredMaxThreads - acceptorThreads - selectorThreads; // ... and the rest are job threads server.setMaxThreads( numCores ); - server.setAddress( new ListenSocketAddress( "localhost", PortAuthority.allocatePort() ) ); + server.setHttpAddress( new ListenSocketAddress( "localhost", PortAuthority.allocatePort() ) ); try { server.start(); diff --git a/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java b/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java index 1a348fd514194..0ef7f4fb0ec43 100644 --- a/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java +++ b/community/shell/src/main/java/org/neo4j/shell/kernel/GraphDatabaseShellServer.java @@ -31,6 +31,7 @@ import org.neo4j.internal.kernel.api.TokenRead; import org.neo4j.kernel.api.KernelTransaction; import org.neo4j.kernel.api.exceptions.Status; +import org.neo4j.kernel.configuration.BoltConnector; import org.neo4j.kernel.impl.core.ThreadToStatementContextBridge; import org.neo4j.kernel.internal.GraphDatabaseAPI; import org.neo4j.shell.Output; @@ -217,14 +218,14 @@ protected String getPrompt( Session session ) throws ShellException private static GraphDatabaseAPI instantiateGraphDb( GraphDatabaseFactory factory, File path, boolean readOnly, String configFileOrNull ) { - GraphDatabaseBuilder builder = factory. - newEmbeddedDatabaseBuilder( path ). - setConfig( GraphDatabaseSettings.disconnected, Boolean.toString( true ) ). - setConfig( GraphDatabaseSettings.read_only, Boolean.toString( readOnly ) ); + GraphDatabaseBuilder builder = factory.newEmbeddedDatabaseBuilder( path ) + .setConfig( GraphDatabaseSettings.read_only, Boolean.toString( readOnly ) ); + if ( configFileOrNull != null ) { builder.loadPropertiesFromFile( configFileOrNull ); } + builder.setConfig( new BoltConnector( "bolt" ).enabled, "false" ); return (GraphDatabaseAPI) builder.newGraphDatabase(); } diff --git a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsBuilder.java b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsBuilder.java index be5e13a315b43..8adf2a65c2fb3 100644 --- a/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsBuilder.java +++ b/enterprise/metrics/src/main/java/org/neo4j/metrics/source/Neo4jMetricsBuilder.java @@ -207,7 +207,8 @@ else if ( mode == OperationalMode.read_replica ) } } - if ( config.get( MetricsSettings.neoServerEnabled ) ) + boolean httpAndHttpsDisabled = config.enabledHttpConnectors().isEmpty(); + if ( !httpAndHttpsDisabled && config.get( MetricsSettings.neoServerEnabled ) ) { life.add( new ServerMetrics( registry, logService, kernelContext.dependencySatisfier() ) ); result = true; diff --git a/enterprise/metrics/src/test/java/org/neo4j/metrics/source/Neo4jMetricsBuilderTest.java b/enterprise/metrics/src/test/java/org/neo4j/metrics/source/Neo4jMetricsBuilderTest.java new file mode 100644 index 0000000000000..0055286a49b61 --- /dev/null +++ b/enterprise/metrics/src/test/java/org/neo4j/metrics/source/Neo4jMetricsBuilderTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j Enterprise Edition. The included source + * code can be redistributed and/or modified under the terms of the + * GNU AFFERO GENERAL PUBLIC LICENSE Version 3 + * (http://www.fsf.org/licensing/licenses/agpl-3.0.html) with the + * Commons Clause, as found in the associated LICENSE.txt file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * Neo4j object code can be licensed independently from the source + * under separate terms from the AGPL. Inquiries can be directed to: + * licensing@neo4j.com + * + * More information is also available at: + * https://neo4j.com/licensing/ + */ +package org.neo4j.metrics.source; + +import com.codahale.metrics.MetricRegistry; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.configuration.HttpConnector; +import org.neo4j.kernel.impl.spi.KernelContext; +import org.neo4j.kernel.impl.spi.SimpleKernelContext; +import org.neo4j.kernel.impl.util.DependencySatisfier; +import org.neo4j.kernel.lifecycle.LifeSupport; +import org.neo4j.logging.internal.NullLogService; +import org.neo4j.metrics.MetricsSettings; +import org.neo4j.metrics.output.EventReporter; +import org.neo4j.metrics.source.server.ServerMetrics; +import org.neo4j.test.extension.Inject; +import org.neo4j.test.extension.TestDirectoryExtension; +import org.neo4j.test.rule.TestDirectory; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.neo4j.kernel.impl.factory.DatabaseInfo.COMMUNITY; + +@ExtendWith( TestDirectoryExtension.class ) +class Neo4jMetricsBuilderTest +{ + @Inject + private TestDirectory testDir; + + @Test + void shouldAddServerMetricsWhenServerEnabled() + { + testBuildingWithServerMetrics( true ); + } + + @Test + void shouldNotAddServerMetricsWhenServerDisabled() + { + testBuildingWithServerMetrics( false ); + } + + private void testBuildingWithServerMetrics( boolean serverMetricsEnabled ) + { + Config config = configWithServerMetrics( serverMetricsEnabled ); + KernelContext kernelContext = new SimpleKernelContext( testDir.databaseDir(), COMMUNITY, mock( DependencySatisfier.class ) ); + LifeSupport life = new LifeSupport(); + + Neo4jMetricsBuilder builder = new Neo4jMetricsBuilder( new MetricRegistry(), mock( EventReporter.class ), config, NullLogService.getInstance(), + kernelContext, mock( Neo4jMetricsBuilder.Dependencies.class ), life ); + + assertTrue( builder.build() ); + + if ( serverMetricsEnabled ) + { + assertThat( life.getLifecycleInstances(), hasItem( instanceOf( ServerMetrics.class ) ) ); + } + else + { + assertThat( life.getLifecycleInstances(), not( hasItem( instanceOf( ServerMetrics.class ) ) ) ); + } + } + + private static Config configWithServerMetrics( boolean enabled ) + { + return Config.builder() + .withSetting( new HttpConnector( "http" ).enabled, Boolean.toString( enabled ) ) + .withSetting( MetricsSettings.neoServerEnabled, "true" ) + .build(); + } +} diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/database/EnterpriseGraphFactory.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/database/EnterpriseGraphFactory.java new file mode 100644 index 0000000000000..3ab752a421682 --- /dev/null +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/database/EnterpriseGraphFactory.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2002-2018 "Neo4j," + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j Enterprise Edition. The included source + * code can be redistributed and/or modified under the terms of the + * GNU AFFERO GENERAL PUBLIC LICENSE Version 3 + * (http://www.fsf.org/licensing/licenses/agpl-3.0.html) with the + * Commons Clause, as found in the associated LICENSE.txt file. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * Neo4j object code can be licensed independently from the source + * under separate terms from the AGPL. Inquiries can be directed to: + * licensing@neo4j.com + * + * More information is also available at: + * https://neo4j.com/licensing/ + */ +package org.neo4j.server.database; + +import java.io.File; + +import org.neo4j.causalclustering.core.CoreGraphDatabase; +import org.neo4j.causalclustering.discovery.DiscoveryServiceFactory; +import org.neo4j.causalclustering.discovery.EnterpriseDiscoveryServiceFactorySelector; +import org.neo4j.causalclustering.readreplica.ReadReplicaGraphDatabase; +import org.neo4j.graphdb.factory.GraphDatabaseSettings; +import org.neo4j.kernel.configuration.Config; +import org.neo4j.kernel.enterprise.EnterpriseGraphDatabase; +import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; +import org.neo4j.kernel.impl.enterprise.configuration.EnterpriseEditionSettings; +import org.neo4j.kernel.impl.factory.GraphDatabaseFacade; + +import static org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; + +public class EnterpriseGraphFactory implements GraphFactory +{ + @Override + public GraphDatabaseFacade newGraphDatabase( Config config, Dependencies dependencies ) + { + EnterpriseEditionSettings.Mode mode = config.get( EnterpriseEditionSettings.mode ); + File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); + DiscoveryServiceFactory discoveryServiceFactory = new EnterpriseDiscoveryServiceFactorySelector().select( config ); + + switch ( mode ) + { + case HA: + return new HighlyAvailableGraphDatabase( storeDir, config, dependencies ); + case ARBITER: + // Should never reach here because this mode is handled separately by the scripts. + throw new IllegalArgumentException( "The server cannot be started in ARBITER mode." ); + case CORE: + return new CoreGraphDatabase( storeDir, config, dependencies, discoveryServiceFactory ); + case READ_REPLICA: + return new ReadReplicaGraphDatabase( storeDir, config, dependencies, discoveryServiceFactory ); + default: + return new EnterpriseGraphDatabase( storeDir, config, dependencies ); + } + } +} diff --git a/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/OpenEnterpriseNeoServer.java b/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/OpenEnterpriseNeoServer.java index bbc49713d95db..2b756d2f26106 100644 --- a/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/OpenEnterpriseNeoServer.java +++ b/enterprise/server-enterprise/src/main/java/org/neo4j/server/enterprise/OpenEnterpriseNeoServer.java @@ -24,7 +24,6 @@ import org.eclipse.jetty.util.thread.ThreadPool; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -32,28 +31,19 @@ import java.util.regex.Pattern; import org.neo4j.causalclustering.core.CausalClusteringSettings; -import org.neo4j.causalclustering.core.CoreGraphDatabase; -import org.neo4j.causalclustering.discovery.DiscoveryServiceFactory; -import org.neo4j.causalclustering.discovery.EnterpriseDiscoveryServiceFactorySelector; -import org.neo4j.causalclustering.readreplica.ReadReplicaGraphDatabase; -import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory; import org.neo4j.graphdb.facade.GraphDatabaseFacadeFactory.Dependencies; -import org.neo4j.graphdb.factory.GraphDatabaseSettings; import org.neo4j.helpers.collection.Iterables; import org.neo4j.kernel.configuration.Config; import org.neo4j.kernel.configuration.ConnectorPortRegister; -import org.neo4j.kernel.enterprise.EnterpriseGraphDatabase; import org.neo4j.kernel.ha.HaSettings; import org.neo4j.kernel.ha.HighlyAvailableGraphDatabase; -import org.neo4j.kernel.impl.enterprise.configuration.EnterpriseEditionSettings; -import org.neo4j.kernel.impl.enterprise.configuration.EnterpriseEditionSettings.Mode; import org.neo4j.kernel.impl.util.UnsatisfiedDependencyException; import org.neo4j.logging.LogProvider; import org.neo4j.metrics.source.server.ServerThreadView; import org.neo4j.metrics.source.server.ServerThreadViewSetter; import org.neo4j.server.CommunityNeoServer; -import org.neo4j.server.database.Database; -import org.neo4j.server.database.LifecycleManagingDatabase.GraphFactory; +import org.neo4j.server.database.EnterpriseGraphFactory; +import org.neo4j.server.database.GraphFactory; import org.neo4j.server.enterprise.modules.EnterpriseAuthorizationModule; import org.neo4j.server.enterprise.modules.JMXManagementModule; import org.neo4j.server.modules.AuthorizationModule; @@ -68,72 +58,17 @@ import org.neo4j.server.web.WebServer; import static org.neo4j.server.configuration.ServerSettings.jmx_module_enabled; -import static org.neo4j.server.database.LifecycleManagingDatabase.lifecycleManagingDatabase; public class OpenEnterpriseNeoServer extends CommunityNeoServer { - - private static final GraphFactory HA_FACTORY = ( config, dependencies ) -> - { - File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); - return new HighlyAvailableGraphDatabase( storeDir, config, dependencies ); - }; - - private static final GraphFactory ENTERPRISE_FACTORY = ( config, dependencies ) -> - { - File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); - return new EnterpriseGraphDatabase( storeDir, config, dependencies ); - }; - - private static GraphFactory coreFactory( DiscoveryServiceFactory discoveryServiceFactory ) - { - return ( config, dependencies ) -> - { - File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); - return new CoreGraphDatabase( storeDir, config, dependencies, discoveryServiceFactory ); - }; - } - - private static GraphFactory readReplicaFactory( DiscoveryServiceFactory discoveryServiceFactory ) - { - return ( config, dependencies ) -> - { - File storeDir = config.get( GraphDatabaseSettings.databases_root_path ); - return new ReadReplicaGraphDatabase( storeDir, config, dependencies, discoveryServiceFactory ); - }; - } - public OpenEnterpriseNeoServer( Config config, Dependencies dependencies, LogProvider logProvider ) { - super( config, createDbFactory( config ), dependencies, logProvider ); - } - - public OpenEnterpriseNeoServer( Config config, Database.Factory dbFactory, GraphDatabaseFacadeFactory.Dependencies - dependencies, LogProvider logProvider ) - { - super( config, dbFactory, dependencies, logProvider ); + super( config, new EnterpriseGraphFactory(), dependencies, logProvider ); } - protected static Database.Factory createDbFactory( Config config ) + public OpenEnterpriseNeoServer( Config config, GraphFactory graphFactory, Dependencies dependencies, LogProvider logProvider ) { - final Mode mode = config.get( EnterpriseEditionSettings.mode ); - - final DiscoveryServiceFactory discoveryServiceFactory = new EnterpriseDiscoveryServiceFactorySelector().select( config ); - - switch ( mode ) - { - case HA: - return lifecycleManagingDatabase( HA_FACTORY ); - case ARBITER: - // Should never reach here because this mode is handled separately by the scripts. - throw new IllegalArgumentException( "The server cannot be started in ARBITER mode." ); - case CORE: - return lifecycleManagingDatabase( coreFactory( discoveryServiceFactory ) ); - case READ_REPLICA: - return lifecycleManagingDatabase( readReplicaFactory( discoveryServiceFactory ) ); - default: - return lifecycleManagingDatabase( ENTERPRISE_FACTORY ); - } + super( config, graphFactory, dependencies, logProvider ); } @Override diff --git a/integrationtests/src/test/java/org/neo4j/TransactionGuardIT.java b/integrationtests/src/test/java/org/neo4j/TransactionGuardIT.java index d95c2ab99dc86..c134f70528edb 100644 --- a/integrationtests/src/test/java/org/neo4j/TransactionGuardIT.java +++ b/integrationtests/src/test/java/org/neo4j/TransactionGuardIT.java @@ -82,7 +82,7 @@ import org.neo4j.logging.NullLogProvider; import org.neo4j.ports.allocation.PortAuthority; import org.neo4j.server.CommunityNeoServer; -import org.neo4j.server.database.LifecycleManagingDatabase; +import org.neo4j.server.database.SimpleGraphFactory; import org.neo4j.server.enterprise.OpenEnterpriseNeoServer; import org.neo4j.server.enterprise.helpers.EnterpriseServerBuilder; import org.neo4j.server.web.HttpHeaderUtils; @@ -665,7 +665,6 @@ void tickAndCheck() private class GuardingServerBuilder extends EnterpriseServerBuilder { private GraphDatabaseFacade graphDatabaseFacade; - final LifecycleManagingDatabase.GraphFactory PRECREATED_FACADE_FACTORY = ( config, dependencies ) -> graphDatabaseFacade; GuardingServerBuilder( GraphDatabaseFacade graphDatabaseAPI ) { @@ -684,8 +683,7 @@ private class GuardTestServer extends OpenEnterpriseNeoServer { GuardTestServer( Config config, GraphDatabaseFacadeFactory.Dependencies dependencies, LogProvider logProvider ) { - super( config, LifecycleManagingDatabase.lifecycleManagingDatabase( PRECREATED_FACADE_FACTORY ), - dependencies, logProvider ); + super( config, new SimpleGraphFactory( graphDatabaseFacade ), dependencies, logProvider ); } } }