public class ManagedMongosLifecycleManager extends AbstractLifecycleManager { private static final Logger LOGGER = LoggerFactory.getLogger(ManagedMongosLifecycleManager.class); public ManagedMongosLifecycleManager() { super(); } private static final String LOCALHOST = "localhost"; protected static final String LOGPATH_ARGUMENT_NAME = "--logpath"; protected static final String PORT_ARGUMENT_NAME = "--port"; protected static final String CHUNK_SIZE_ARGUMENT_NAME = "--chunkSize"; protected static final String CONFIG_DB_ARGUMENT_NAME = "--configdb"; protected static final String DEFAULT_MONGO_LOGPATH = "logpath"; protected static final String DEFAULT_MONGO_TARGET_PATH = "target" + File.separatorChar + "mongo-temp"; protected static final int DEFAULT_CHUNK_SIZE = 1; protected static final String MONGODB_BINARY_DIRECTORY = "bin"; protected static final String MONGOS_EXECUTABLE_X = "mongos"; protected static final String MONGOS_EXECUTABLE_W = "mongos.exe"; private static final String DEFAULT_PATH = "mongos"; private String mongosPath = SystemEnvironmentVariables.getEnvironmentOrPropertyVariable("MONGO_HOME"); private int chunkSize = DEFAULT_CHUNK_SIZE; private int port = DBPort.PORT; private String targetPath = DEFAULT_MONGO_TARGET_PATH; private String logRelativePath = DEFAULT_MONGO_LOGPATH; private List<String> configDatabases = new ArrayList<String>(); private Map<String, String> extraCommandArguments = new HashMap<String, String>(); private List<String> singleCommandArguments = new ArrayList<String>(); private CommandLineExecutor commandLineExecutor = new CommandLineExecutor(); private OperatingSystemResolver operatingSystemResolver = new OsNameSystemPropertyOperatingSystemResolver(); private MongoDbLowLevelOps mongoDbLowLevelOps = MongoDbLowLevelOpsFactory.getSingletonInstance(); private ProcessRunnable processRunnable; @Override public String getHost() { return LOCALHOST; } @Override public int getPort() { return this.port; } @Override public void doStart() throws Throwable { LOGGER.info("Starting {} Mongos instance.", mongosPath); File dbPath = ensureDbPathDoesNotExitsAndReturnCompositePath(); if (dbPath.mkdirs()) { startMongoDBAsADaemon(); boolean isServerUp = assertThatConnectionToMongoDbIsPossible(); if (!isServerUp) { throw new IllegalStateException( "Couldn't establish a connection with " + this.mongosPath + " server at /127.0.0.1:" + port); } } else { throw new IllegalStateException("Db Path " + dbPath + " could not be created."); } LOGGER.info("Started {} Mongos instance.", mongosPath); } @Override public void doStop() { LOGGER.info("Stopping {} Mongos instance.", mongosPath); try { if (this.processRunnable != null) { this.processRunnable.destroyProcess(); } } finally { ensureDbPathDoesNotExitsAndReturnCompositePath(); } LOGGER.info("Stopped {} Mongos instance.", mongosPath); } private List<String> startMongoDBAsADaemon() throws InterruptedException { CountDownLatch processIsReady = new CountDownLatch(1); processRunnable = new ProcessRunnable(processIsReady); Thread thread = new Thread(processRunnable); thread.start(); processIsReady.await(); return processRunnable.consoleOutput; } private List<String> buildOperationSystemProgramAndArguments() { List<String> programAndArguments = new ArrayList<String>(); programAndArguments.add(getExecutablePath()); programAndArguments.add(PORT_ARGUMENT_NAME); programAndArguments.add(Integer.toString(port)); programAndArguments.add(LOGPATH_ARGUMENT_NAME); programAndArguments.add(logRelativePath); programAndArguments.add(CHUNK_SIZE_ARGUMENT_NAME); programAndArguments.add(Integer.toString(chunkSize)); programAndArguments.add(CONFIG_DB_ARGUMENT_NAME); programAndArguments.add(joinFrom(this.configDatabases).trim()); for (String argument : this.singleCommandArguments) { programAndArguments.add(argument); } for (String argumentName : this.extraCommandArguments.keySet()) { programAndArguments.add(argumentName); programAndArguments.add(this.extraCommandArguments.get(argumentName)); } return programAndArguments; } private String getExecutablePath() { return this.mongosPath + File.separatorChar + MONGODB_BINARY_DIRECTORY + File.separatorChar + mongoExecutable(); } private String mongoExecutable() { OperatingSystem operatingSystem = this.operatingSystemResolver.currentOperatingSystem(); switch (operatingSystem.getFamily()) { case WINDOWS: return MONGOS_EXECUTABLE_W; default: return MONGOS_EXECUTABLE_X; } } private boolean assertThatConnectionToMongoDbIsPossible() throws InterruptedException, UnknownHostException { return this.mongoDbLowLevelOps.assertThatConnectionIsPossible(LOCALHOST, port); } private File ensureDbPathDoesNotExitsAndReturnCompositePath() { File dbPath = new File(targetPath + File.separatorChar + DEFAULT_PATH); if (dbPath.exists()) { deleteDir(dbPath); } return dbPath; } public void setLogRelativePath(String logRelativePath) { this.logRelativePath = logRelativePath; } public void setMongosPath(String mongodPath) { this.mongosPath = mongodPath; } public void setTargetPath(String targetPath) { this.targetPath = targetPath; } public void addExtraCommandLineArgument(String argumentName, String argumentValue) { this.extraCommandArguments.put(argumentName, argumentValue); } public void addSingleCommandLineArgument(String argument) { this.singleCommandArguments.add(argument); } public void setPort(int port) { this.port = port; } public void setChunkSize(int chunkSize) { this.chunkSize = chunkSize; } public void addConfigurationDatabase(String hostAndPort) { this.configDatabases.add(hostAndPort); } protected String getMongosPath() { return mongosPath; } protected boolean areConfigDatabasesDefined() { return configDatabases.size() > 0; } protected void setCommandLineExecutor(CommandLineExecutor commandLineExecutor) { this.commandLineExecutor = commandLineExecutor; } protected void setOperatingSystemResolver(OperatingSystemResolver operatingSystemResolver) { this.operatingSystemResolver = operatingSystemResolver; } protected void setMongoDbLowLevelOps(MongoDbLowLevelOps mongoDbLowLevelOps) { this.mongoDbLowLevelOps = mongoDbLowLevelOps; } public class ProcessRunnable implements Runnable { private CountDownLatch processIsReady; private List<String> consoleOutput; private Process process; public ProcessRunnable(CountDownLatch processIsReady) { this.processIsReady = processIsReady; } @Override public void run() { try { process = startProcess(); // consoleOutput = getConsoleOutput(process); } catch (IOException e) { throw prepareException(e); } finally { processIsReady.countDown(); } try { process.waitFor(); if (process.exitValue() != 0) { LOGGER.info( "Mongos [" + mongosPath + PORT_ARGUMENT_NAME + port + LOGPATH_ARGUMENT_NAME + logRelativePath + "] console output is: " + consoleOutput); } } catch (InterruptedException ie) { throw prepareException(ie); } } public void destroyProcess() { if (this.process != null) { this.process.destroy(); } } private IllegalStateException prepareException(Exception e) { return new IllegalStateException( "Mongos [" + mongosPath + PORT_ARGUMENT_NAME + port + LOGPATH_ARGUMENT_NAME + logRelativePath + "] could not be started. Next console message was thrown: " + e.getMessage()); } private Process startProcess() throws IOException { return commandLineExecutor.startProcessInDirectoryAndArguments( targetPath, buildOperationSystemProgramAndArguments()); } private List<String> getConsoleOutput(Process pwd) throws IOException { return commandLineExecutor.getConsoleOutput(pwd); } } }
public class ReplicaSetManagedMongoDb extends ExternalResource { private static final Logger LOGGER = LoggerFactory.getLogger(ReplicaSetManagedMongoDb.class); private ReplicaSetGroup replicaSetGroup; private MongoDbLowLevelOps mongoDbLowLevelOps = MongoDbLowLevelOpsFactory.getSingletonInstance(); protected ReplicaSetManagedMongoDb(ReplicaSetGroup replicaSetGroup) { this.replicaSetGroup = replicaSetGroup; } public String replicaSetName() { return this.replicaSetGroup.getReplicaSetName(); } public List<ManagedMongoDbLifecycleManager> getReplicaSetServers() { return this.replicaSetGroup.getServers(); } public void shutdownServer(int port) { ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager = replicaSetGroup.getStartedServer(port); if (managedMongoDbLifecycleManager != null) { managedMongoDbLifecycleManager.stopEngine(); } } public void waitUntilReplicaSetBecomesStable() { MongoClient mongoClient; try { mongoClient = getAvailableServersMongoClient(); } catch (UnknownHostException e) { throw new IllegalArgumentException(e); } waitingToBecomeStable(mongoClient); mongoClient.close(); } private void waitingToBecomeStable(MongoClient mongoClient) { if (replicaSetGroup.isAuthenticationSet()) { this.mongoDbLowLevelOps.waitUntilReplicaSetBecomeStable( mongoClient, this.replicaSetGroup.numberOfStartedServers(), replicaSetGroup.getUsername(), replicaSetGroup.getPassword()); } else { this.mongoDbLowLevelOps.waitUntilReplicaSetBecomeStable( mongoClient, this.replicaSetGroup.numberOfStartedServers()); } } public void startupServer(int port) throws Throwable { ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager = replicaSetGroup.getStoppedServer(port); if (managedMongoDbLifecycleManager != null) { managedMongoDbLifecycleManager.startEngine(); } } public ManagedMongoDbLifecycleManager getServerByPortAndState(int port, boolean state) { if (state) { return replicaSetGroup.getStartedServer(port); } else { return replicaSetGroup.getStoppedServer(port); } } @Override protected void before() throws Throwable { wakeUpServers(); replicaSetInitiate(); waitUntilConfigurationSpreadAcrossServersFromDefaultConnection(); } public void startAllReplicaSet() throws Throwable { this.before(); } private void waitUntilConfigurationSpreadAcrossServersFromDefaultConnection() throws UnknownHostException { MongoClient mongoClient = getDefaultMongoClient(); waitingToBecomeStable(mongoClient); mongoClient.close(); } @Override protected void after() { shutdownServers(); } public void stopAllReplicaSet() { this.after(); } protected List<ManagedMongoDbLifecycleManager> getServers() { return replicaSetGroup.getServers(); } protected ConfigurationDocument getConfigurationDocument() { return replicaSetGroup.getConfiguration(); } private void replicaSetInitiate() throws UnknownHostException { CommandResult commandResult = runCommandToAdmin(getConfigurationDocument()); LOGGER.info("Command {} has returned {}", "replSetInitiaite", commandResult.toString()); } private CommandResult runCommandToAdmin(ConfigurationDocument cmd) throws UnknownHostException { MongoClient mongoClient = getDefaultMongoClient(); CommandResult commandResult = null; if (this.replicaSetGroup.isAuthenticationSet()) { commandResult = MongoDbCommands.replicaSetInitiate( mongoClient, cmd, this.replicaSetGroup.getUsername(), this.replicaSetGroup.getPassword()); } else { commandResult = MongoDbCommands.replicaSetInitiate(mongoClient, cmd); } mongoClient.close(); return commandResult; } private void shutdownServers() { LOGGER.info("Stopping Replica Set servers"); for (ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager : replicaSetGroup.getServers()) { if (isServerStarted(managedMongoDbLifecycleManager)) { managedMongoDbLifecycleManager.stopEngine(); } } LOGGER.info("Stopped Replica Set servers"); } private void wakeUpServers() throws Throwable { LOGGER.info("Starting Replica Set servers"); for (ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager : replicaSetGroup.getServers()) { if (isServerStopped(managedMongoDbLifecycleManager)) { managedMongoDbLifecycleManager.startEngine(); } } LOGGER.info("Started Replica Set servers"); } private boolean isServerStarted(ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager) { return managedMongoDbLifecycleManager.isReady(); } private boolean isServerStopped(ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager) { return !managedMongoDbLifecycleManager.isReady(); } private MongoClient getAvailableServersMongoClient() throws UnknownHostException { List<ServerAddress> seeds = new ArrayList<ServerAddress>(); for (ManagedMongoDbLifecycleManager managedMongoDbLifecycleManager : replicaSetGroup.getServers()) { if (managedMongoDbLifecycleManager.isReady()) { ServerAddress serverAddress = new ServerAddress( managedMongoDbLifecycleManager.getHost(), managedMongoDbLifecycleManager.getPort()); seeds.add(serverAddress); } } return new MongoClient(seeds); } private MongoClient getDefaultMongoClient() throws UnknownHostException { ManagedMongoDbLifecycleManager defaultConnection = replicaSetGroup.getDefaultConnection(); return new MongoClient(defaultConnection.getHost(), defaultConnection.getPort()); } }