org.neo4j.server.helpers.CommunityServerBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.neo4j.server.helpers.CommunityServerBuilder.java

Source

/*
 * Copyright (c) 2002-2015 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.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 <http://www.gnu.org/licenses/>.
 */
package org.neo4j.server.helpers;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.neo4j.helpers.Clock;
import org.neo4j.helpers.FakeClock;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.kernel.GraphDatabaseAPI;
import org.neo4j.kernel.GraphDatabaseDependencies;
import org.neo4j.kernel.InternalAbstractGraphDatabase;
import org.neo4j.kernel.InternalAbstractGraphDatabase.Dependencies;
import org.neo4j.logging.Log;
import org.neo4j.logging.LogProvider;
import org.neo4j.logging.NullLogProvider;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.server.CommunityNeoServer;
import org.neo4j.server.ServerTestUtils;
import org.neo4j.server.configuration.ConfigurationBuilder;
import org.neo4j.server.configuration.Configurator;
import org.neo4j.server.configuration.PropertyFileConfigurator;
import org.neo4j.server.configuration.ServerSettings;
import org.neo4j.server.database.Database;
import org.neo4j.server.database.LifecycleManagingDatabase;
import org.neo4j.server.preflight.PreFlightTasks;
import org.neo4j.server.preflight.PreflightTask;
import org.neo4j.server.rest.paging.LeaseManager;
import org.neo4j.server.rest.web.DatabaseActions;
import org.neo4j.server.web.ServerInternalSettings;
import org.neo4j.test.ImpermanentGraphDatabase;

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static org.neo4j.helpers.Clock.SYSTEM_CLOCK;
import static org.neo4j.server.ServerTestUtils.asOneLine;
import static org.neo4j.server.ServerTestUtils.createTempPropertyFile;
import static org.neo4j.server.ServerTestUtils.writePropertiesToFile;
import static org.neo4j.server.ServerTestUtils.writePropertyToFile;
import static org.neo4j.server.database.LifecycleManagingDatabase.EMBEDDED;
import static org.neo4j.server.database.LifecycleManagingDatabase.lifecycleManagingDatabase;

public class CommunityServerBuilder {
    protected final LogProvider logProvider;
    private String portNo = "7474";
    private String maxThreads = null;
    protected String dbDir = null;
    private String webAdminUri = "/db/manage/";
    private String webAdminDataUri = "/db/data/";
    protected PreFlightTasks preflightTasks;
    private final HashMap<String, String> thirdPartyPackages = new HashMap<>();
    private final Properties arbitraryProperties = new Properties();

    public static LifecycleManagingDatabase.GraphFactory IN_MEMORY_DB = new LifecycleManagingDatabase.GraphFactory() {
        @Override
        public GraphDatabaseAPI newGraphDatabase(String storeDir, Map<String, String> params,
                Dependencies dependencies) {
            params.put(InternalAbstractGraphDatabase.Configuration.ephemeral.name(), "true");
            return new ImpermanentGraphDatabase(storeDir, params, dependencies);
        }
    };

    private static enum WhatToDo {
        CREATE_GOOD_TUNING_FILE, CREATE_DANGLING_TUNING_FILE_PROPERTY, CREATE_CORRUPT_TUNING_FILE
    }

    private WhatToDo action;
    protected Clock clock = null;
    private String[] autoIndexedNodeKeys = null;
    private String[] autoIndexedRelationshipKeys = null;
    private String host = null;
    private String[] securityRuleClassNames;
    public boolean persistent;
    private Boolean httpsEnabled = FALSE;

    public static CommunityServerBuilder server(LogProvider logProvider) {
        return new CommunityServerBuilder(logProvider);
    }

    public static CommunityServerBuilder server() {
        return new CommunityServerBuilder(NullLogProvider.getInstance());
    }

    public CommunityNeoServer build() throws IOException {
        if (dbDir == null && persistent) {
            throw new IllegalStateException("Must specify path");
        }
        final File configFile = buildBefore();

        Log log = logProvider.getLog(getClass());
        ConfigurationBuilder configurator = new PropertyFileConfigurator(configFile, log);
        Monitors monitors = new Monitors();
        return build(configFile, configurator,
                GraphDatabaseDependencies.newDependencies().userLogProvider(logProvider).monitors(monitors));
    }

    protected CommunityNeoServer build(File configFile, ConfigurationBuilder configurator,
            Dependencies dependencies) {
        return new TestCommunityNeoServer(configurator, configFile, dependencies, logProvider);
    }

    public File createPropertiesFiles() throws IOException {
        File temporaryConfigFile = createTempPropertyFile();

        createPropertiesFile(temporaryConfigFile);
        createTuningFile(temporaryConfigFile);

        return temporaryConfigFile;
    }

    public CommunityServerBuilder withClock(Clock clock) {
        this.clock = clock;
        return this;
    }

    private void createPropertiesFile(File temporaryConfigFile) {
        Map<String, String> properties = MapUtil.stringMap(Configurator.MANAGEMENT_PATH_PROPERTY_KEY, webAdminUri,
                Configurator.REST_API_PATH_PROPERTY_KEY, webAdminDataUri);
        if (dbDir != null) {
            properties.put(Configurator.DATABASE_LOCATION_PROPERTY_KEY, dbDir);
        }

        if (portNo != null) {
            properties.put(Configurator.WEBSERVER_PORT_PROPERTY_KEY, portNo);
        }
        if (host != null) {
            properties.put(Configurator.WEBSERVER_ADDRESS_PROPERTY_KEY, host);
        }
        if (maxThreads != null) {
            properties.put(Configurator.WEBSERVER_MAX_THREADS_PROPERTY_KEY, maxThreads);
        }

        if (thirdPartyPackages.keySet().size() > 0) {
            properties.put(Configurator.THIRD_PARTY_PACKAGES_KEY, asOneLine(thirdPartyPackages));
        }

        if (autoIndexedNodeKeys != null && autoIndexedNodeKeys.length > 0) {
            properties.put("node_auto_indexing", "true");
            String propertyKeys = org.apache.commons.lang.StringUtils.join(autoIndexedNodeKeys, ",");
            properties.put("node_keys_indexable", propertyKeys);
        }

        if (autoIndexedRelationshipKeys != null && autoIndexedRelationshipKeys.length > 0) {
            properties.put("relationship_auto_indexing", "true");
            String propertyKeys = org.apache.commons.lang.StringUtils.join(autoIndexedRelationshipKeys, ",");
            properties.put("relationship_keys_indexable", propertyKeys);
        }

        if (securityRuleClassNames != null && securityRuleClassNames.length > 0) {
            String propertyKeys = org.apache.commons.lang.StringUtils.join(securityRuleClassNames, ",");
            properties.put(Configurator.SECURITY_RULES_KEY, propertyKeys);
        }

        if (httpsEnabled != null) {
            if (httpsEnabled) {
                properties.put(Configurator.WEBSERVER_HTTPS_ENABLED_PROPERTY_KEY, "true");
            } else {
                properties.put(Configurator.WEBSERVER_HTTPS_ENABLED_PROPERTY_KEY, "false");
            }
        }

        properties.put(ServerSettings.auth_enabled.name(), "false");
        properties.put(ServerInternalSettings.auth_store.name(), "neo4j-home/data/dbms/authorization");

        for (Object key : arbitraryProperties.keySet()) {
            properties.put(String.valueOf(key), String.valueOf(arbitraryProperties.get(key)));
        }

        ServerTestUtils.writePropertiesToFile(properties, temporaryConfigFile);
    }

    private void createTuningFile(File temporaryConfigFile) throws IOException {
        if (action == WhatToDo.CREATE_GOOD_TUNING_FILE) {
            File databaseTuningPropertyFile = createTempPropertyFile();
            Map<String, String> properties = MapUtil.stringMap("neostore.nodestore.db.mapped_memory", "25M",
                    "neostore.relationshipstore.db.mapped_memory", "50M", "neostore.propertystore.db.mapped_memory",
                    "90M", "neostore.propertystore.db.strings.mapped_memory", "130M",
                    "neostore.propertystore.db.arrays.mapped_memory", "130M");
            writePropertiesToFile(properties, databaseTuningPropertyFile);
            writePropertyToFile(Configurator.DB_TUNING_PROPERTY_FILE_KEY,
                    databaseTuningPropertyFile.getAbsolutePath(), temporaryConfigFile);
        } else if (action == WhatToDo.CREATE_DANGLING_TUNING_FILE_PROPERTY) {
            writePropertyToFile(Configurator.DB_TUNING_PROPERTY_FILE_KEY,
                    createTempPropertyFile().getAbsolutePath(), temporaryConfigFile);
        } else if (action == WhatToDo.CREATE_CORRUPT_TUNING_FILE) {
            File corruptTuningFile = trashFile();
            writePropertyToFile(Configurator.DB_TUNING_PROPERTY_FILE_KEY, corruptTuningFile.getAbsolutePath(),
                    temporaryConfigFile);
        }
    }

    private File trashFile() throws IOException {
        File f = createTempPropertyFile();

        try (FileWriter fstream = new FileWriter(f, true); BufferedWriter out = new BufferedWriter(fstream)) {
            for (int i = 0; i < 100; i++) {
                out.write((int) System.currentTimeMillis());
            }
        }

        return f;
    }

    protected CommunityServerBuilder(LogProvider logProvider) {
        this.logProvider = logProvider;
    }

    public CommunityServerBuilder persistent() {
        this.persistent = true;
        return this;
    }

    public CommunityServerBuilder onPort(int portNo) {
        this.portNo = String.valueOf(portNo);
        return this;
    }

    public CommunityServerBuilder withMaxJettyThreads(int maxThreads) {
        this.maxThreads = String.valueOf(maxThreads);
        return this;
    }

    public CommunityServerBuilder usingDatabaseDir(String dbDir) {
        this.dbDir = dbDir;
        return this;
    }

    public CommunityServerBuilder withRelativeWebAdminUriPath(String webAdminUri) {
        try {
            URI theUri = new URI(webAdminUri);
            if (theUri.isAbsolute()) {
                this.webAdminUri = theUri.getPath();
            } else {
                this.webAdminUri = theUri.toString();
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        return this;
    }

    public CommunityServerBuilder withRelativeWebDataAdminUriPath(String webAdminDataUri) {
        try {
            URI theUri = new URI(webAdminDataUri);
            if (theUri.isAbsolute()) {
                this.webAdminDataUri = theUri.getPath();
            } else {
                this.webAdminDataUri = theUri.toString();
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
        return this;
    }

    public CommunityServerBuilder withFailingPreflightTasks() {
        preflightTasks = new PreFlightTasks(NullLogProvider.getInstance()) {
            @Override
            public boolean run() {
                return false;
            }

            @Override
            public PreflightTask failedTask() {
                return new PreflightTask() {

                    @Override
                    public String getFailureMessage() {
                        return "mockFailure";
                    }

                    @Override
                    public boolean run() {
                        return false;
                    }
                };
            }
        };
        return this;
    }

    public CommunityServerBuilder withDefaultDatabaseTuning() {
        action = WhatToDo.CREATE_GOOD_TUNING_FILE;
        return this;
    }

    public CommunityServerBuilder withNonResolvableTuningFile() {
        action = WhatToDo.CREATE_DANGLING_TUNING_FILE_PROPERTY;
        return this;
    }

    public CommunityServerBuilder withCorruptTuningFile() {
        action = WhatToDo.CREATE_CORRUPT_TUNING_FILE;
        return this;
    }

    public CommunityServerBuilder withThirdPartyJaxRsPackage(String packageName, String mountPoint) {
        thirdPartyPackages.put(packageName, mountPoint);
        return this;
    }

    public CommunityServerBuilder withFakeClock() {
        clock = new FakeClock();
        return this;
    }

    public CommunityServerBuilder withAutoIndexingEnabledForNodes(String... keys) {
        autoIndexedNodeKeys = keys;
        return this;
    }

    public CommunityServerBuilder withAutoIndexingEnabledForRelationships(String... keys) {
        autoIndexedRelationshipKeys = keys;
        return this;
    }

    public CommunityServerBuilder onHost(String host) {
        this.host = host;
        return this;
    }

    public CommunityServerBuilder withSecurityRules(String... securityRuleClassNames) {
        this.securityRuleClassNames = securityRuleClassNames;
        return this;
    }

    public CommunityServerBuilder withHttpsEnabled() {
        httpsEnabled = TRUE;
        return this;
    }

    public CommunityServerBuilder withProperty(String key, String value) {
        arbitraryProperties.put(key, value);
        return this;
    }

    public CommunityServerBuilder withPreflightTasks(PreflightTask... tasks) {
        this.preflightTasks = new PreFlightTasks(NullLogProvider.getInstance(), tasks);
        return this;
    }

    protected DatabaseActions createDatabaseActionsObject(Database database, ConfigurationBuilder configurator) {
        Clock clockToUse = (clock != null) ? clock : SYSTEM_CLOCK;

        return new DatabaseActions(new LeaseManager(clockToUse),
                configurator.configuration().get(ServerInternalSettings.script_sandboxing_enabled),
                database.getGraph());
    }

    protected File buildBefore() throws IOException {
        File configFile = createPropertiesFiles();

        if (preflightTasks == null) {
            preflightTasks = new PreFlightTasks(NullLogProvider.getInstance()) {
                @Override
                public boolean run() {
                    return true;
                }
            };
        }
        return configFile;
    }

    private class TestCommunityNeoServer extends CommunityNeoServer {
        private final File configFile;

        private TestCommunityNeoServer(ConfigurationBuilder propertyFileConfigurator, File configFile,
                Dependencies dependencies, LogProvider logProvider) {
            super(propertyFileConfigurator, lifecycleManagingDatabase(persistent ? EMBEDDED : IN_MEMORY_DB),
                    dependencies, logProvider);
            this.configFile = configFile;
        }

        @Override
        protected PreFlightTasks createPreflightTasks() {
            return preflightTasks;
        }

        @Override
        protected DatabaseActions createDatabaseActions() {
            return createDatabaseActionsObject(database, configurator);
        }

        @Override
        public void stop() {
            super.stop();
            configFile.delete();
        }
    }
}