
info.archinnov.achilles.script.ScriptExecutor Maven / Gradle / Ivy
package info.archinnov.achilles.script;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.SimpleStatement;
import com.datastax.driver.core.Statement;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static info.archinnov.achilles.internals.statement.StatementHelper.isDMLStatement;
import static info.archinnov.achilles.logger.AchillesLoggers.ACHILLES_DDL_SCRIPT;
import static info.archinnov.achilles.logger.AchillesLoggers.ACHILLES_DML_STATEMENT;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import info.archinnov.achilles.internals.futures.FutureUtils;
import info.archinnov.achilles.validation.Validator;
/**
* Facility class to execute a CQL script file or a plain CQL statement
*/
public class ScriptExecutor {
private static final Logger DML_LOGGER = LoggerFactory.getLogger(ACHILLES_DML_STATEMENT);
private static final Logger DDL_LOGGER = LoggerFactory.getLogger(ACHILLES_DDL_SCRIPT);
private static final String COMMA = ";";
private static final String BATCH_BEGIN = "BEGIN";
private static final String BATCH_APPLY = "APPLY";
private static final String CODE_DELIMITER_START = "^\\s*(?:AS)?\\s*\\$\\$\\s*$";
private static final String CODE_DELIMITER_END = "^\\s*\\$\\$\\s*;\\s*$";
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{([a-z][a-zA-Z0-9_]*)\\}");
private static final Map EMPTY_MAP = new HashMap<>();
private final ExecutorService sameThreadExecutor = MoreExecutors.newDirectExecutorService();
private final Session session;
public ScriptExecutor(Session session) {
this.session = session;
}
/**
* Execute a CQL script file located in the class path
*
* @param scriptLocation the location of the script file in the class path
*/
public void executeScript(String scriptLocation) {
executeScriptTemplate(scriptLocation, EMPTY_MAP);
}
/**
* Execute a CQL script template located in the class path and
* inject provided values into the template to produce the actual script
*
* @param scriptTemplateLocation the location of the script template in the class path
* @param values template values
*/
public void executeScriptTemplate(String scriptTemplateLocation, Map values) {
final List statements = buildStatements(loadScriptAsLines(scriptTemplateLocation, values));
for (SimpleStatement statement : statements) {
if (isDMLStatement(statement)) {
DML_LOGGER.debug("\tSCRIPT : {}", statement.getQueryString());
} else {
DDL_LOGGER.debug("\t\tSCRIPT : {}", statement.getQueryString());
}
session.execute(statement);
}
}
/**
* Execute a plain CQL string statement
* @param statement
* plain CQL string statement
*
* @return the resultSet
*
*/
public ResultSet execute(String statement) {
return session.execute(statement);
}
/**
* Execute a CQL statement
* @param statement
* CQL statement
*
* @return the resultSet
*
*/
public ResultSet execute(Statement statement) {
return session.execute(statement);
}
/**
* Execute a plain CQL string statement asynchronously
*
* @param statement the CQL string statement
* @return CompletableFuture<ResultSet>
*/
public CompletableFuture executeAsync(String statement) {
return FutureUtils.toCompletableFuture(session.executeAsync(statement), sameThreadExecutor);
}
/**
* Execute a CQL statement asynchronously
*
* @param statement CQL statement
* @return CompletableFuture<ResultSet>
*/
public CompletableFuture executeAsync(Statement statement) {
return FutureUtils.toCompletableFuture(session.executeAsync(statement), sameThreadExecutor);
}
protected List loadScriptAsLines(String scriptLocation) {
return loadScriptAsLines(scriptLocation, EMPTY_MAP);
}
protected List loadScriptAsLines(String scriptLocation, Map variables) {
InputStream inputStream = this.getClass().getResourceAsStream("/" + scriptLocation);
Validator.validateNotNull(inputStream, "Cannot find CQL script file at location '%s'", scriptLocation);
Scanner scanner = new Scanner(inputStream);
List lines = new ArrayList<>();
while (scanner.hasNextLine()) {
String nextLine = maybeReplaceVariables(scanner, variables);
if (isNotBlank(nextLine)) {
lines.add(nextLine);
}
}
return lines;
}
private String maybeReplaceVariables(Scanner scanner, Map variables) {
String nextLine = scanner.nextLine().trim();
if (isNotBlank(nextLine) && !variables.isEmpty()) {
final Matcher matcher = VARIABLE_PATTERN.matcher(nextLine);
while (matcher.find()) {
final String group = matcher.group(1);
Validator.validateTrue(variables.containsKey(group),
"Cannot find value for variable ${%s} in the variable map provided to ScriptExecutor", group);
nextLine = nextLine.replaceFirst("\\$\\{" + group + "\\}", variables.get(group).toString());
}
}
return nextLine;
}
protected List buildStatements(List lines) {
List statements = new ArrayList<>();
StringBuilder statement = new StringBuilder();
boolean batch = false;
boolean codeBlock = false;
StringBuilder batchStatement = new StringBuilder();
for (String line : lines) {
if (line.trim().startsWith(BATCH_BEGIN)) {
batch = true;
}
if (line.trim().matches(CODE_DELIMITER_START)) {
if(codeBlock) {
codeBlock = false;
} else {
codeBlock = true;
}
}
if (batch) {
batchStatement.append(line);
if (line.trim().startsWith(BATCH_APPLY)) {
batch = false;
statements.add(new SimpleStatement(batchStatement.toString()));
batchStatement = new StringBuilder();
}
} else if(codeBlock) {
statement.append(line);
if (line.trim().matches(CODE_DELIMITER_END)) {
codeBlock = false;
statements.add(new SimpleStatement(statement.toString()));
statement = new StringBuilder();
}
}
else {
statement.append(line);
if (line.trim().endsWith(COMMA)) {
statements.add(new SimpleStatement(statement.toString()));
statement = new StringBuilder();
} else {
statement.append(" ");
}
}
}
return statements;
}
public Session getSession() {
return session;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy