com.espertech.esper.core.deploy.EPDeploymentAdminImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of esper Show documentation
Show all versions of esper Show documentation
Complex event processing and event series analysis component
/*
***************************************************************************************
* Copyright (C) 2006 EsperTech, Inc. All rights reserved. *
* http://www.espertech.com/esper *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
***************************************************************************************
*/
package com.espertech.esper.core.deploy;
import com.espertech.esper.client.ConfigurationEngineDefaults;
import com.espertech.esper.client.EPException;
import com.espertech.esper.client.EPServiceProviderIsolated;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.deploy.*;
import com.espertech.esper.core.service.EPAdministratorSPI;
import com.espertech.esper.core.service.StatementEventTypeRef;
import com.espertech.esper.core.service.StatementIsolationService;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.filter.FilterService;
import com.espertech.esper.util.DependencyGraph;
import com.espertech.esper.util.ManagedReadWriteLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
/**
* Deployment administrative implementation.
*/
public class EPDeploymentAdminImpl implements EPDeploymentAdminSPI {
private final static Logger log = LoggerFactory.getLogger(EPDeploymentAdminImpl.class);
private final EPAdministratorSPI epService;
private final ManagedReadWriteLock eventProcessingRWLock;
private final DeploymentStateService deploymentStateService;
private final StatementEventTypeRef statementEventTypeRef;
private final EventAdapterService eventAdapterService;
private final StatementIsolationService statementIsolationService;
private final FilterService filterService;
private final TimeZone timeZone;
private final ConfigurationEngineDefaults.ExceptionHandling.UndeployRethrowPolicy undeployRethrowPolicy;
public EPDeploymentAdminImpl(EPAdministratorSPI epService, ManagedReadWriteLock eventProcessingRWLock, DeploymentStateService deploymentStateService, StatementEventTypeRef statementEventTypeRef, EventAdapterService eventAdapterService, StatementIsolationService statementIsolationService, FilterService filterService, TimeZone timeZone, ConfigurationEngineDefaults.ExceptionHandling.UndeployRethrowPolicy undeployRethrowPolicy) {
this.epService = epService;
this.eventProcessingRWLock = eventProcessingRWLock;
this.deploymentStateService = deploymentStateService;
this.statementEventTypeRef = statementEventTypeRef;
this.eventAdapterService = eventAdapterService;
this.statementIsolationService = statementIsolationService;
this.filterService = filterService;
this.timeZone = timeZone;
this.undeployRethrowPolicy = undeployRethrowPolicy;
}
public Module read(InputStream stream, String uri) throws IOException, ParseException {
if (log.isDebugEnabled()) {
log.debug("Reading module from input stream");
}
return EPLModuleUtil.readInternal(stream, uri);
}
public Module read(File file) throws IOException, ParseException {
if (log.isDebugEnabled()) {
log.debug("Reading resource '" + file.getAbsolutePath() + "'");
}
return EPLModuleUtil.readFile(file);
}
public Module read(URL url) throws IOException, ParseException {
if (log.isDebugEnabled()) {
log.debug("Reading resource from url: " + url.toString());
}
return EPLModuleUtil.readInternal(url.openStream(), url.toString());
}
public Module read(String resource) throws IOException, ParseException {
if (log.isDebugEnabled()) {
log.debug("Reading resource '" + resource + "'");
}
return EPLModuleUtil.readResource(resource, eventAdapterService.getEngineImportService());
}
public synchronized DeploymentResult deploy(Module module, DeploymentOptions options, String assignedDeploymentId) throws DeploymentActionException, DeploymentLockException, InterruptedException {
if (deploymentStateService.getDeployment(assignedDeploymentId) != null) {
throw new IllegalArgumentException("Assigned deployment id '" + assignedDeploymentId + "' is already in use");
}
return deployInternal(module, options, assignedDeploymentId, Calendar.getInstance(timeZone));
}
public synchronized DeploymentResult deploy(Module module, DeploymentOptions options) throws DeploymentActionException, DeploymentLockException, InterruptedException {
String deploymentId = deploymentStateService.nextDeploymentId();
return deployInternal(module, options, deploymentId, Calendar.getInstance(timeZone));
}
private DeploymentResult deployInternal(Module module, DeploymentOptions options, String deploymentId, Calendar addedDate) throws DeploymentActionException, DeploymentLockException, InterruptedException {
if (options == null) {
options = new DeploymentOptions();
}
options.getDeploymentLockStrategy().acquire(eventProcessingRWLock);
try {
return deployInternalLockTaken(module, options, deploymentId, addedDate);
} finally {
options.getDeploymentLockStrategy().release(eventProcessingRWLock);
}
}
private DeploymentResult deployInternalLockTaken(Module module, DeploymentOptions options, String deploymentId, Calendar addedDate) throws DeploymentActionException {
if (log.isDebugEnabled()) {
log.debug("Deploying module " + module);
}
List imports;
if (module.getImports() != null) {
for (String imported : module.getImports()) {
if (log.isDebugEnabled()) {
log.debug("Adding import " + imported);
}
epService.getConfiguration().addImport(imported);
}
imports = new ArrayList(module.getImports());
} else {
imports = Collections.emptyList();
}
if (options.isCompile()) {
List exceptions = new ArrayList();
for (ModuleItem item : module.getItems()) {
if (item.isCommentOnly()) {
continue;
}
try {
epService.compileEPL(item.getExpression());
} catch (RuntimeException ex) {
exceptions.add(new DeploymentItemException(ex.getMessage(), item.getExpression(), ex, item.getLineNumber()));
}
}
if (!exceptions.isEmpty()) {
throw buildException("Compilation failed", module, exceptions);
}
}
if (options.isCompileOnly()) {
return null;
}
List exceptions = new ArrayList();
List statementNames = new ArrayList();
List statements = new ArrayList();
Set eventTypesReferenced = new HashSet();
for (ModuleItem item : module.getItems()) {
if (item.isCommentOnly()) {
continue;
}
String statementName = null;
Object userObject = null;
if (options.getStatementNameResolver() != null || options.getStatementUserObjectResolver() != null) {
StatementDeploymentContext ctx = new StatementDeploymentContext(item.getExpression(), module, item, deploymentId);
statementName = options.getStatementNameResolver() != null ? options.getStatementNameResolver().getStatementName(ctx) : null;
userObject = options.getStatementUserObjectResolver() != null ? options.getStatementUserObjectResolver().getUserObject(ctx) : null;
}
try {
EPStatement stmt;
if (options.getIsolatedServiceProvider() == null) {
stmt = epService.createEPL(item.getExpression(), statementName, userObject);
} else {
EPServiceProviderIsolated unit = statementIsolationService.getIsolationUnit(options.getIsolatedServiceProvider(), -1);
stmt = unit.getEPAdministrator().createEPL(item.getExpression(), statementName, userObject);
}
statementNames.add(new DeploymentInformationItem(stmt.getName(), stmt.getText()));
statements.add(stmt);
String[] types = statementEventTypeRef.getTypesForStatementName(stmt.getName());
if (types != null) {
eventTypesReferenced.addAll(Arrays.asList(types));
}
} catch (EPException ex) {
exceptions.add(new DeploymentItemException(ex.getMessage(), item.getExpression(), ex, item.getLineNumber()));
if (options.isFailFast()) {
break;
}
}
}
if (!exceptions.isEmpty()) {
if (options.isRollbackOnFail()) {
log.debug("Rolling back intermediate statements for deployment");
for (EPStatement stmt : statements) {
try {
stmt.destroy();
} catch (Exception ex) {
log.debug("Failed to destroy created statement during rollback: " + ex.getMessage(), ex);
}
}
EPLModuleUtil.undeployTypes(eventTypesReferenced, statementEventTypeRef, eventAdapterService, filterService);
}
String text = "Deployment failed";
if (options.isValidateOnly()) {
text = "Validation failed";
}
throw buildException(text, module, exceptions);
}
if (options.isValidateOnly()) {
log.debug("Rolling back created statements for validate-only");
for (EPStatement stmt : statements) {
try {
stmt.destroy();
} catch (Exception ex) {
log.debug("Failed to destroy created statement during rollback: " + ex.getMessage(), ex);
}
}
EPLModuleUtil.undeployTypes(eventTypesReferenced, statementEventTypeRef, eventAdapterService, filterService);
return null;
}
DeploymentInformationItem[] deploymentInfoArr = statementNames.toArray(new DeploymentInformationItem[statementNames.size()]);
DeploymentInformation desc = new DeploymentInformation(deploymentId, module, addedDate, Calendar.getInstance(timeZone), deploymentInfoArr, DeploymentState.DEPLOYED);
deploymentStateService.addUpdateDeployment(desc);
if (log.isDebugEnabled()) {
log.debug("Module " + module + " was successfully deployed.");
}
return new DeploymentResult(desc.getDeploymentId(), Collections.unmodifiableList(statements), imports);
}
private DeploymentActionException buildException(String msg, Module module, List exceptions) {
String message = msg;
if (module.getName() != null) {
message += " in module '" + module.getName() + "'";
}
if (module.getUri() != null) {
message += " in module url '" + module.getUri() + "'";
}
if (exceptions.size() > 0) {
message += " in expression '" + getAbbreviated(exceptions.get(0).getExpression()) + "' : " + exceptions.get(0).getMessage();
}
return new DeploymentActionException(message, exceptions);
}
private String getAbbreviated(String expression) {
if (expression.length() < 60) {
return replaceNewline(expression);
}
String subtext = expression.substring(0, 50) + "...(" + expression.length() + " chars)";
return replaceNewline(subtext);
}
private String replaceNewline(String text) {
text = text.replaceAll("\\n", " ");
text = text.replaceAll("\\t", " ");
text = text.replaceAll("\\r", " ");
return text;
}
public Module parse(String eplModuleText) throws IOException, ParseException {
return EPLModuleUtil.parseInternal(eplModuleText, null);
}
public synchronized UndeploymentResult undeployRemove(String deploymentId) throws DeploymentNotFoundException {
return undeployRemoveInternal(deploymentId, new UndeploymentOptions());
}
public synchronized UndeploymentResult undeployRemove(String deploymentId, UndeploymentOptions undeploymentOptions) throws DeploymentNotFoundException {
return undeployRemoveInternal(deploymentId, undeploymentOptions == null ? new UndeploymentOptions() : undeploymentOptions);
}
public synchronized UndeploymentResult undeploy(String deploymentId) throws DeploymentStateException, DeploymentNotFoundException, DeploymentLockException, InterruptedException {
return undeployInternal(deploymentId, new UndeploymentOptions());
}
public synchronized UndeploymentResult undeploy(String deploymentId, UndeploymentOptions undeploymentOptions) throws DeploymentException, InterruptedException {
return undeployInternal(deploymentId, undeploymentOptions == null ? new UndeploymentOptions() : undeploymentOptions);
}
public synchronized String[] getDeployments() {
return deploymentStateService.getDeployments();
}
public synchronized DeploymentInformation getDeployment(String deploymentId) {
return deploymentStateService.getDeployment(deploymentId);
}
public synchronized DeploymentInformation[] getDeploymentInformation() {
return deploymentStateService.getAllDeployments();
}
public synchronized DeploymentOrder getDeploymentOrder(Collection modules, DeploymentOrderOptions options) throws DeploymentOrderException {
if (options == null) {
options = new DeploymentOrderOptions();
}
String[] deployments = deploymentStateService.getDeployments();
List proposedModules = new ArrayList();
proposedModules.addAll(modules);
Set availableModuleNames = new HashSet();
for (Module proposedModule : proposedModules) {
if (proposedModule.getName() != null) {
availableModuleNames.add(proposedModule.getName());
}
}
// Collect all uses-dependencies of existing modules
Map> usesPerModuleName = new HashMap>();
for (String deployment : deployments) {
DeploymentInformation info = deploymentStateService.getDeployment(deployment);
if (info == null) {
continue;
}
if ((info.getModule().getName() == null) || (info.getModule().getUses() == null)) {
continue;
}
Set usesSet = usesPerModuleName.get(info.getModule().getName());
if (usesSet == null) {
usesSet = new HashSet();
usesPerModuleName.put(info.getModule().getName(), usesSet);
}
usesSet.addAll(info.getModule().getUses());
}
// Collect uses-dependencies of proposed modules
for (Module proposedModule : proposedModules) {
// check uses-dependency is available
if (options.isCheckUses()) {
if (proposedModule.getUses() != null) {
for (String uses : proposedModule.getUses()) {
if (availableModuleNames.contains(uses)) {
continue;
}
if (isDeployed(uses)) {
continue;
}
String message = "Module-dependency not found";
if (proposedModule.getName() != null) {
message += " as declared by module '" + proposedModule.getName() + "'";
}
message += " for uses-declaration '" + uses + "'";
throw new DeploymentOrderException(message);
}
}
}
if ((proposedModule.getName() == null) || (proposedModule.getUses() == null)) {
continue;
}
Set usesSet = usesPerModuleName.get(proposedModule.getName());
if (usesSet == null) {
usesSet = new HashSet();
usesPerModuleName.put(proposedModule.getName(), usesSet);
}
usesSet.addAll(proposedModule.getUses());
}
Map> proposedModuleNames = new HashMap>();
int count = 0;
for (Module proposedModule : proposedModules) {
SortedSet moduleNumbers = proposedModuleNames.get(proposedModule.getName());
if (moduleNumbers == null) {
moduleNumbers = new TreeSet();
proposedModuleNames.put(proposedModule.getName(), moduleNumbers);
}
moduleNumbers.add(count);
count++;
}
DependencyGraph graph = new DependencyGraph(proposedModules.size(), false);
int fromModule = 0;
for (Module proposedModule : proposedModules) {
if ((proposedModule.getUses() == null) || (proposedModule.getUses().isEmpty())) {
fromModule++;
continue;
}
SortedSet dependentModuleNumbers = new TreeSet();
for (String use : proposedModule.getUses()) {
SortedSet moduleNumbers = proposedModuleNames.get(use);
if (moduleNumbers == null) {
continue;
}
dependentModuleNumbers.addAll(moduleNumbers);
}
dependentModuleNumbers.remove(fromModule);
graph.addDependency(fromModule, dependentModuleNumbers);
fromModule++;
}
if (options.isCheckCircularDependency()) {
Stack circular = graph.getFirstCircularDependency();
if (circular != null) {
String message = "";
String delimiter = "";
for (int i : circular) {
message += delimiter;
message += "module '" + proposedModules.get(i).getName() + "'";
delimiter = " uses (depends on) ";
}
throw new DeploymentOrderException("Circular dependency detected in module uses-relationships: " + message);
}
}
List reverseDeployList = new ArrayList();
Set ignoreList = new HashSet();
while (ignoreList.size() < proposedModules.size()) {
// seconardy sort according to the order of listing
Set rootNodes = new TreeSet(new Comparator() {
public int compare(Integer o1, Integer o2) {
return -1 * o1.compareTo(o2);
}
});
rootNodes.addAll(graph.getRootNodes(ignoreList));
if (rootNodes.isEmpty()) { // circular dependency could cause this
for (int i = 0; i < proposedModules.size(); i++) {
if (!ignoreList.contains(i)) {
rootNodes.add(i);
break;
}
}
}
for (Integer root : rootNodes) {
ignoreList.add(root);
reverseDeployList.add(proposedModules.get(root));
}
}
Collections.reverse(reverseDeployList);
return new DeploymentOrder(reverseDeployList);
}
public synchronized boolean isDeployed(String moduleName) {
DeploymentInformation[] infos = deploymentStateService.getAllDeployments();
if (infos == null) {
return false;
}
for (DeploymentInformation info : infos) {
if ((info.getModule().getName() != null) && (info.getModule().getName().equals(moduleName))) {
return info.getState() == DeploymentState.DEPLOYED;
}
}
return false;
}
public synchronized DeploymentResult readDeploy(InputStream stream, String moduleURI, String moduleArchive, Object userObject) throws IOException, ParseException, DeploymentOrderException, DeploymentActionException, DeploymentLockException, InterruptedException {
Module module = EPLModuleUtil.readInternal(stream, moduleURI);
return deployQuick(module, moduleURI, moduleArchive, userObject);
}
public synchronized DeploymentResult readDeploy(String resource, String moduleURI, String moduleArchive, Object userObject) throws IOException, ParseException, DeploymentOrderException, DeploymentActionException, DeploymentLockException, InterruptedException {
Module module = read(resource);
return deployQuick(module, moduleURI, moduleArchive, userObject);
}
public synchronized DeploymentResult parseDeploy(String eplModuleText) throws IOException, ParseException, DeploymentException, InterruptedException {
return parseDeploy(eplModuleText, null, null, null);
}
public synchronized DeploymentResult parseDeploy(String buffer, String moduleURI, String moduleArchive, Object userObject) throws IOException, ParseException, DeploymentOrderException, DeploymentActionException, DeploymentLockException, InterruptedException {
Module module = EPLModuleUtil.parseInternal(buffer, moduleURI);
return deployQuick(module, moduleURI, moduleArchive, userObject);
}
public synchronized void add(Module module, String assignedDeploymentId) {
if (deploymentStateService.getDeployment(assignedDeploymentId) != null) {
throw new IllegalArgumentException("Assigned deployment id '" + assignedDeploymentId + "' is already in use");
}
addInternal(module, assignedDeploymentId);
}
public synchronized String add(Module module) {
String deploymentId = deploymentStateService.nextDeploymentId();
addInternal(module, deploymentId);
return deploymentId;
}
private void addInternal(Module module, String deploymentId) {
DeploymentInformation desc = new DeploymentInformation(deploymentId, module, Calendar.getInstance(timeZone), Calendar.getInstance(timeZone), new DeploymentInformationItem[0], DeploymentState.UNDEPLOYED);
deploymentStateService.addUpdateDeployment(desc);
}
public synchronized DeploymentResult deploy(String deploymentId, DeploymentOptions options) throws DeploymentNotFoundException, DeploymentStateException, DeploymentOrderException, DeploymentActionException, DeploymentLockException, InterruptedException {
DeploymentInformation info = deploymentStateService.getDeployment(deploymentId);
if (info == null) {
throw new DeploymentNotFoundException("Deployment by id '" + deploymentId + "' could not be found");
}
if (info.getState() == DeploymentState.DEPLOYED) {
throw new DeploymentStateException("Module by deployment id '" + deploymentId + "' is already in deployed state");
}
getDeploymentOrder(Collections.singletonList(info.getModule()), null);
return deployInternal(info.getModule(), options, deploymentId, info.getAddedDate());
}
public synchronized void remove(String deploymentId) throws DeploymentStateException, DeploymentNotFoundException {
DeploymentInformation info = deploymentStateService.getDeployment(deploymentId);
if (info == null) {
throw new DeploymentNotFoundException("Deployment by id '" + deploymentId + "' could not be found");
}
if (info.getState() == DeploymentState.DEPLOYED) {
throw new DeploymentStateException("Deployment by id '" + deploymentId + "' is in deployed state, please undeploy first");
}
deploymentStateService.remove(deploymentId);
}
private synchronized UndeploymentResult undeployRemoveInternal(String deploymentId, UndeploymentOptions options) throws DeploymentNotFoundException {
DeploymentInformation info = deploymentStateService.getDeployment(deploymentId);
if (info == null) {
throw new DeploymentNotFoundException("Deployment by id '" + deploymentId + "' could not be found");
}
UndeploymentResult result;
if (info.getState() == DeploymentState.DEPLOYED) {
result = undeployRemoveInternal(info, options);
} else {
result = new UndeploymentResult(deploymentId, Collections.emptyList());
}
deploymentStateService.remove(deploymentId);
return result;
}
private UndeploymentResult undeployInternal(String deploymentId, UndeploymentOptions undeploymentOptions) throws DeploymentStateException, DeploymentNotFoundException, DeploymentLockException, InterruptedException {
undeploymentOptions.getDeploymentLockStrategy().acquire(eventProcessingRWLock);
try {
return undeployInternalLockTaken(deploymentId, undeploymentOptions);
} finally {
undeploymentOptions.getDeploymentLockStrategy().release(eventProcessingRWLock);
}
}
private UndeploymentResult undeployInternalLockTaken(String deploymentId, UndeploymentOptions undeploymentOptions) throws DeploymentStateException, DeploymentNotFoundException {
DeploymentInformation info = deploymentStateService.getDeployment(deploymentId);
if (info == null) {
throw new DeploymentNotFoundException("Deployment by id '" + deploymentId + "' could not be found");
}
if (info.getState() == DeploymentState.UNDEPLOYED) {
throw new DeploymentStateException("Deployment by id '" + deploymentId + "' is already in undeployed state");
}
UndeploymentResult result = undeployRemoveInternal(info, undeploymentOptions);
DeploymentInformation updated = new DeploymentInformation(deploymentId, info.getModule(), info.getAddedDate(), Calendar.getInstance(timeZone), new DeploymentInformationItem[0], DeploymentState.UNDEPLOYED);
deploymentStateService.addUpdateDeployment(updated);
return result;
}
private UndeploymentResult undeployRemoveInternal(DeploymentInformation info, UndeploymentOptions undeploymentOptions) {
DeploymentInformationItem[] reverted = new DeploymentInformationItem[info.getItems().length];
for (int i = 0; i < info.getItems().length; i++) {
reverted[i] = info.getItems()[info.getItems().length - 1 - i];
}
List revertedStatements = new ArrayList();
if (undeploymentOptions.isDestroyStatements()) {
Set referencedTypes = new HashSet();
RuntimeException firstExceptionEncountered = null;
for (DeploymentInformationItem item : reverted) {
EPStatement statement = epService.getStatement(item.getStatementName());
if (statement == null) {
log.debug("Deployment id '" + info.getDeploymentId() + "' statement name '" + item + "' not found");
continue;
}
referencedTypes.addAll(Arrays.asList(statementEventTypeRef.getTypesForStatementName(statement.getName())));
if (statement.isDestroyed()) {
continue;
}
try {
statement.destroy();
} catch (RuntimeException ex) {
log.warn("Unexpected exception destroying statement: " + ex.getMessage(), ex);
if (firstExceptionEncountered == null) {
firstExceptionEncountered = ex;
}
}
revertedStatements.add(item);
}
EPLModuleUtil.undeployTypes(referencedTypes, statementEventTypeRef, eventAdapterService, filterService);
Collections.reverse(revertedStatements);
if (firstExceptionEncountered != null && undeployRethrowPolicy == ConfigurationEngineDefaults.ExceptionHandling.UndeployRethrowPolicy.RETHROW_FIRST) {
throw firstExceptionEncountered;
}
}
return new UndeploymentResult(info.getDeploymentId(), revertedStatements);
}
private DeploymentResult deployQuick(Module module, String moduleURI, String moduleArchive, Object userObject) throws IOException, ParseException, DeploymentOrderException, DeploymentActionException, DeploymentLockException, InterruptedException {
module.setUri(moduleURI);
module.setArchiveName(moduleArchive);
module.setUserObject(userObject);
getDeploymentOrder(Collections.singletonList(module), null);
return deploy(module, null);
}
}