org.janusgraph.diskstorage.cql.CassandraStorageSetup.java Source code

Java tutorial

Introduction

Here is the source code for org.janusgraph.diskstorage.cql.CassandraStorageSetup.java

Source

// Copyright 2017 JanusGraph Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.janusgraph.diskstorage.cql;

import static org.janusgraph.diskstorage.cql.CQLConfigOptions.KEYSPACE;
import static org.janusgraph.diskstorage.cql.CQLConfigOptions.SSL_ENABLED;
import static org.janusgraph.diskstorage.cql.CQLConfigOptions.SSL_TRUSTSTORE_LOCATION;
import static org.janusgraph.diskstorage.cql.CQLConfigOptions.SSL_TRUSTSTORE_PASSWORD;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.CONNECTION_TIMEOUT;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.DROP_ON_CLEAR;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.PAGE_SIZE;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.STORAGE_BACKEND;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.STORAGE_HOSTS;
import static org.janusgraph.graphdb.configuration.GraphDatabaseConfiguration.buildGraphConfiguration;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.time.Duration;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.io.FileUtils;
import org.janusgraph.diskstorage.StandardStoreManager;
import org.janusgraph.diskstorage.cassandra.utils.CassandraDaemonWrapper;
import org.janusgraph.diskstorage.configuration.ConfigElement;
import org.janusgraph.diskstorage.configuration.ModifiableConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;

public class CassandraStorageSetup {

    private static final Logger LOGGER = LoggerFactory.getLogger(CassandraStorageSetup.class);

    public static final String CONFDIR_SYSPROP = "test.cassandra.confdir";
    public static final String DATADIR_SYSPROP = "test.cassandra.datadir";
    public static final String HOSTNAME = System.getProperty(ConfigElement.getPath(STORAGE_HOSTS));

    static {
        setWrapperStoreManager();
    }

    private static volatile Paths paths;

    /**
     * Load cassandra.yaml and data paths from the environment or from default values if nothing is set in the environment, then delete all
     * existing data, and finally start Cassandra.
     * <p>
     * This method is idempotent. Calls after the first have no effect aside from logging statements.
     */
    public static void startCleanEmbedded() {
        if (HOSTNAME == null) {
            final Paths p = getPaths();
            if (!CassandraDaemonWrapper.isStarted()) {
                try {
                    FileUtils.deleteDirectory(new File(p.dataPath));
                    FileUtils.deleteQuietly(
                            new File((new File(p.dataPath)).getParent() + File.separator + "commitlog"));
                } catch (final IOException e) {
                    throw new RuntimeException(e);
                }
            }
            CassandraDaemonWrapper.start(p.yamlPath);
        }
    }

    private static synchronized Paths getPaths() {
        if (null == paths) {
            final String yamlPath = "file://" + loadAbsoluteDirectoryPath("conf", CONFDIR_SYSPROP, true)
                    + File.separator + "cassandra.yaml";
            final String dataPath = loadAbsoluteDirectoryPath("data", DATADIR_SYSPROP, false);
            paths = new Paths(yamlPath, dataPath);
        }
        return paths;
    }

    private static String loadAbsoluteDirectoryPath(final String name, final String prop,
            final boolean mustExistAndBeAbsolute) {
        String s = System.getProperty(prop);

        if (null == s) {
            s = Joiner.on(File.separator).join(System.getProperty("user.dir"), "target", "cassandra",
                    "byteorderedpartitioner", name);
            LOGGER.info("Set default Cassandra {} directory path {}", name, s);
        } else {
            LOGGER.info("Loaded Cassandra {} directory path {} from system property {}", name, s, prop);
        }

        if (mustExistAndBeAbsolute) {
            final File dir = new File(s);
            Preconditions.checkArgument(dir.isDirectory(), "Path %s must be a directory", s);
            Preconditions.checkArgument(dir.isAbsolute(), "Path %s must be absolute", s);
        }

        return s;
    }

    public static ModifiableConfiguration getCQLConfiguration(final String keyspace) {
        final ModifiableConfiguration config = buildGraphConfiguration();
        config.set(KEYSPACE, cleanKeyspaceName(keyspace));
        LOGGER.debug("Set keyspace name: {}", config.get(KEYSPACE));
        config.set(PAGE_SIZE, 500);
        config.set(CONNECTION_TIMEOUT, Duration.ofSeconds(60L));
        config.set(STORAGE_BACKEND, "cql");
        if (HOSTNAME != null)
            config.set(STORAGE_HOSTS, new String[] { HOSTNAME });
        config.set(DROP_ON_CLEAR, false);
        return config;
    }

    public static ModifiableConfiguration enableSSL(final ModifiableConfiguration mc) {
        mc.set(SSL_ENABLED, true);
        mc.set(STORAGE_HOSTS, new String[] { HOSTNAME != null ? HOSTNAME : "127.0.0.1" });
        mc.set(SSL_TRUSTSTORE_LOCATION,
                Joiner.on(File.separator).join("target", "cassandra", "murmur-ssl", "conf", "test.truststore"));
        mc.set(SSL_TRUSTSTORE_PASSWORD, "cassandra");
        return mc;
    }

    /**
     * Cassandra only accepts keyspace names 48 characters long or shorter made up of alphanumeric characters and underscores.
     */
    private static String cleanKeyspaceName(final String raw) {
        Preconditions.checkNotNull(raw);
        Preconditions.checkArgument(0 < raw.length());

        if (48 < raw.length() || raw.matches("^.*[^a-zA-Z0-9_].*$")) {
            return "strhash" + String.valueOf(Math.abs(raw.hashCode()));
        } else {
            return raw;
        }
    }

    private static void setWrapperStoreManager() {
        try {
            final Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);

            Field field = StandardStoreManager.class.getDeclaredField("managerClass");
            field.setAccessible(true);
            field.set(StandardStoreManager.CQL, CachingCQLStoreManager.class.getCanonicalName());

            field = StandardStoreManager.class.getDeclaredField("ALL_SHORTHANDS");
            field.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            field.set(null, ImmutableList.copyOf(StandardStoreManager.CQL.getShorthands()));

            field = StandardStoreManager.class.getDeclaredField("ALL_MANAGER_CLASSES");
            field.setAccessible(true);
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
            field.set(null, ImmutableMap.of(StandardStoreManager.CQL.getShorthands().get(0),
                    StandardStoreManager.CQL.getManagerClass()));
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException("Unable to set wrapper CQL store manager", e);
        }
    }

    private static class Paths {

        private final String yamlPath;
        private final String dataPath;

        public Paths(final String yamlPath, final String dataPath) {
            this.yamlPath = yamlPath;
            this.dataPath = dataPath;
        }
    }
}