com.lordofthejars.nosqlunit.cassandra.EmbeddedCassandraServerHelper Maven / Gradle / Ivy
package com.lordofthejars.nosqlunit.cassandra;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import me.prettyprint.cassandra.service.CassandraHostConfigurator;
import me.prettyprint.hector.api.Cluster;
import me.prettyprint.hector.api.ddl.KeyspaceDefinition;
import me.prettyprint.hector.api.factory.HFactory;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.commitlog.CommitLog;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.service.CassandraDaemon;
import org.apache.commons.lang.StringUtils;
import org.apache.thrift.transport.TTransportException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class EmbeddedCassandraServerHelper {
private static Logger log = LoggerFactory.getLogger(EmbeddedCassandraServerHelper.class);
public static final String DEFAULT_TMP_DIR = "target/embeddedCassandra";
public static final String DEFAULT_CASSANDRA_YML_FILE = "cu-cassandra.yaml";
private static final String INTERNAL_CASSANDRA_KEYSPACE = "system";
private static CassandraDaemon cassandraDaemon = null;
static ExecutorService executor = Executors.newSingleThreadExecutor();
public EmbeddedCassandraServerHelper() {
super();
}
public void startEmbeddedCassandra() throws TTransportException, IOException, InterruptedException,
ConfigurationException {
startEmbeddedCassandra(DEFAULT_CASSANDRA_YML_FILE);
}
public void startEmbeddedCassandra(String yamlFile) throws TTransportException, IOException, ConfigurationException {
startEmbeddedCassandra(yamlFile, DEFAULT_TMP_DIR);
}
/**
* Set embedded cassandra up and spawn it in a new thread.
*
* @throws TTransportException
* @throws IOException
* @throws InterruptedException
*/
public void startEmbeddedCassandra(String yamlFile, String tmpDir) throws TTransportException, IOException, ConfigurationException {
if (!StringUtils.startsWith(yamlFile, "/")) {
yamlFile = "/" + yamlFile;
}
if (cassandraDaemon == null) {
log.debug("Starting cassandra...");
log.debug("Initialization needed");
rmdir(tmpDir);
copy("/log4j-embedded-cassandra.properties", tmpDir);
copy(yamlFile, tmpDir);
System.setProperty("cassandra.config", "file:" + tmpDir + yamlFile);
System.setProperty("log4j.configuration", "file:" + tmpDir + "/log4j-embedded-cassandra.properties");
System.setProperty("cassandra-foreground", "true");
cleanupAndLeaveDirs();
final CountDownLatch startupLatch = new CountDownLatch(1);
executor.execute(new Runnable() {
@Override
public void run() {
cassandraDaemon = new CassandraDaemon();
cassandraDaemon.activate();
startupLatch.countDown();
}
});
try {
startupLatch.await(10, SECONDS);
} catch (InterruptedException e) {
log.error("Interrupted waiting for Cassandra daemon to start:", e);
throw new AssertionError(e);
}
} else {
/* nothing to do Cassandra is already started */
}
}
/**
* stop the embedded cassandra
*/
public void stopEmbeddedCassandra() {
if (cassandraDaemon != null) {
cassandraDaemon.stop();
}
executor.shutdown();
executor.shutdownNow();
log.debug("Cassandra is stopped");
}
/**
* drop all keyspaces (expect system)
*/
public static void cleanEmbeddedCassandra() {
dropKeyspaces();
}
private static void dropKeyspaces() {
String host = DatabaseDescriptor.getRpcAddress().getHostName();
int port = DatabaseDescriptor.getRpcPort();
log.debug("Cleaning cassandra keyspaces on " + host + ":" + port);
Cluster cluster = HFactory.getOrCreateCluster("TestCluster", new CassandraHostConfigurator(host + ":" + port));
/* get all keyspace */
List keyspaces = cluster.describeKeyspaces();
/* drop all keyspace except internal cassandra keyspace */
for (KeyspaceDefinition keyspaceDefinition : keyspaces) {
String keyspaceName = keyspaceDefinition.getName();
if (!INTERNAL_CASSANDRA_KEYSPACE.equals(keyspaceName)) {
cluster.dropKeyspace(keyspaceName);
}
}
}
private static void rmdir(String dir) throws IOException {
File dirFile = new File(dir);
if (dirFile.exists()) {
FileUtils.deleteRecursive(new File(dir));
}
}
/**
* Copies a resource from within the jar to a directory.
*
* @param resource
* @param directory
* @throws IOException
*/
private static void copy(String resource, String directory) throws IOException {
mkdir(directory);
InputStream is = EmbeddedCassandraServerHelper.class.getResourceAsStream(resource);
String fileName = resource.substring(resource.lastIndexOf("/") + 1);
File file = new File(directory + System.getProperty("file.separator") + fileName);
OutputStream out = new FileOutputStream(file);
byte buf[] = new byte[1024];
int len;
while ((len = is.read(buf)) > 0) {
out.write(buf, 0, len);
}
out.close();
is.close();
}
/**
* Creates a directory
*
* @param dir
* @throws IOException
*/
private static void mkdir(String dir) throws IOException {
FileUtils.createDirectory(dir);
}
private static void cleanupAndLeaveDirs() throws IOException {
mkdirs();
cleanup();
mkdirs();
CommitLog.instance.resetUnsafe(); // cleanup screws w/ CommitLog, this
// brings it back to safe state
}
private static void cleanup() throws IOException {
// clean up commitlog
String[] directoryNames = { DatabaseDescriptor.getCommitLogLocation(), };
for (String dirName : directoryNames) {
File dir = new File(dirName);
if (!dir.exists())
throw new RuntimeException("No such directory: " + dir.getAbsolutePath());
FileUtils.deleteRecursive(dir);
}
// clean up data directory which are stored as data directory/table/data
// files
for (String dirName : DatabaseDescriptor.getAllDataFileLocations()) {
File dir = new File(dirName);
if (!dir.exists())
throw new RuntimeException("No such directory: " + dir.getAbsolutePath());
FileUtils.deleteRecursive(dir);
}
}
public static void mkdirs() {
DatabaseDescriptor.createAllDirectories();
}
}