/*
***************************************************************************************
* 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.service;
import com.espertech.esper.client.EPException;
import com.espertech.esper.client.EPServiceIsolationException;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.core.service.resource.StatementResourceHolder;
import com.espertech.esper.core.service.resource.StatementResourceService;
import com.espertech.esper.epl.spec.SelectClauseStreamSelectorEnum;
import com.espertech.esper.epl.spec.StatementSpecRaw;
import com.espertech.esper.filter.FilterSet;
import com.espertech.esper.schedule.ScheduleSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* Implementation for the admin interface.
*/
public class EPAdministratorIsolatedImpl implements EPAdministratorIsolatedSPI {
private static Logger log = LoggerFactory.getLogger(EPAdministratorIsolatedImpl.class);
private final String isolatedServiceName;
private final EPIsolationUnitServices services;
private final EPServicesContext unisolatedServices;
private final EPRuntimeIsolatedSPI isolatedRuntime;
private final Set<String> statementNames = Collections.synchronizedSet(new HashSet<String>());
/**
* Ctor.
*
* @param isolatedServiceName name of the isolated service
* @param services isolated services
* @param unisolatedServices engine services
* @param isolatedRuntime the runtime for this isolated service
*/
public EPAdministratorIsolatedImpl(String isolatedServiceName, EPIsolationUnitServices services, EPServicesContext unisolatedServices, EPRuntimeIsolatedSPI isolatedRuntime) {
this.isolatedServiceName = isolatedServiceName;
this.services = services;
this.unisolatedServices = unisolatedServices;
this.isolatedRuntime = isolatedRuntime;
}
public EPStatement createEPL(String eplStatement, String statementName, Object userObject) throws EPException {
return createEPLStatementId(eplStatement, statementName, userObject, null);
}
public EPStatement createEPLStatementId(String eplStatement, String statementName, Object userObject, Integer optionalStatementId) throws EPException {
SelectClauseStreamSelectorEnum defaultStreamSelector = SelectClauseStreamSelectorEnum.mapFromSODA(unisolatedServices.getConfigSnapshot().getEngineDefaults().getStreamSelection().getDefaultStreamSelector());
StatementSpecRaw statementSpec = EPAdministratorHelper.compileEPL(eplStatement, eplStatement, true, statementName, unisolatedServices, defaultStreamSelector);
EPStatement statement = unisolatedServices.getStatementLifecycleSvc().createAndStart(statementSpec, eplStatement, false, statementName, userObject, services, optionalStatementId, null);
EPStatementSPI stmtSpi = (EPStatementSPI) statement;
stmtSpi.getStatementContext().setInternalEventEngineRouteDest(isolatedRuntime);
stmtSpi.setServiceIsolated(isolatedServiceName);
statementNames.add(stmtSpi.getName());
return statement;
}
public String[] getStatementNames() {
return statementNames.toArray(new String[statementNames.size()]);
}
public void addStatement(String name) {
statementNames.add(name); // for recovery
}
public void addStatement(EPStatement stmt) {
addStatement(new EPStatement[]{stmt});
}
public void addStatement(EPStatement[] stmt) {
unisolatedServices.getEventProcessingRWLock().acquireWriteLock();
try {
long fromTime = unisolatedServices.getSchedulingService().getTime();
long toTime = services.getSchedulingService().getTime();
long delta = toTime - fromTime;
// perform checking
Set<Integer> statementIds = new HashSet<Integer>();
for (EPStatement aStmt : stmt) {
if (aStmt == null) {
throw new EPServiceIsolationException("Illegal argument, a null value was provided in the statement list");
}
EPStatementSPI stmtSpi = (EPStatementSPI) aStmt;
statementIds.add(stmtSpi.getStatementId());
if (aStmt.getServiceIsolated() != null) {
throw new EPServiceIsolationException("Statement named '" + aStmt.getName() + "' already in service isolation under '" + stmtSpi.getServiceIsolated() + "'");
}
}
// start txn
unisolatedServices.getStatementIsolationService().beginIsolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
FilterSet filters = unisolatedServices.getFilterService().take(statementIds);
ScheduleSet schedules = unisolatedServices.getSchedulingService().take(statementIds);
services.getFilterService().apply(filters);
services.getSchedulingService().apply(schedules);
for (EPStatement aStmt : stmt) {
EPStatementSPI stmtSpi = (EPStatementSPI) aStmt;
stmtSpi.getStatementContext().setFilterService(services.getFilterService());
stmtSpi.getStatementContext().setSchedulingService(services.getSchedulingService());
stmtSpi.getStatementContext().setInternalEventEngineRouteDest(isolatedRuntime);
stmtSpi.getStatementContext().getScheduleAdjustmentService().adjust(delta);
statementNames.add(stmtSpi.getName());
stmtSpi.setServiceIsolated(isolatedServiceName);
applyFilterVersion(stmtSpi, services.getFilterService().getFiltersVersion());
}
// commit txn
unisolatedServices.getStatementIsolationService().commitIsolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
} catch (EPServiceIsolationException ex) {
throw ex;
} catch (RuntimeException ex) {
unisolatedServices.getStatementIsolationService().rollbackIsolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
String message = "Unexpected exception taking statements: " + ex.getMessage();
log.error(message, ex);
throw new EPException(message, ex);
} finally {
unisolatedServices.getEventProcessingRWLock().releaseWriteLock();
}
}
public void removeStatement(EPStatement stmt) {
removeStatement(new EPStatement[]{stmt});
}
public void removeStatement(EPStatement[] stmt) {
unisolatedServices.getEventProcessingRWLock().acquireWriteLock();
try {
long fromTime = services.getSchedulingService().getTime();
long toTime = unisolatedServices.getSchedulingService().getTime();
long delta = toTime - fromTime;
Set<Integer> statementIds = new HashSet<Integer>();
for (EPStatement aStmt : stmt) {
if (aStmt == null) {
throw new EPServiceIsolationException("Illegal argument, a null value was provided in the statement list");
}
EPStatementSPI stmtSpi = (EPStatementSPI) aStmt;
statementIds.add(stmtSpi.getStatementId());
if (aStmt.getServiceIsolated() == null) {
throw new EPServiceIsolationException("Statement named '" + aStmt.getName() + "' is not currently in service isolation");
}
if (!aStmt.getServiceIsolated().equals(isolatedServiceName)) {
throw new EPServiceIsolationException("Statement named '" + aStmt.getName() + "' not in this service isolation but under service isolation '" + aStmt.getName() + "'");
}
}
// start txn
unisolatedServices.getStatementIsolationService().beginUnisolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
FilterSet filters = services.getFilterService().take(statementIds);
ScheduleSet schedules = services.getSchedulingService().take(statementIds);
unisolatedServices.getFilterService().apply(filters);
unisolatedServices.getSchedulingService().apply(schedules);
for (EPStatement aStmt : stmt) {
EPStatementSPI stmtSpi = (EPStatementSPI) aStmt;
stmtSpi.getStatementContext().setFilterService(unisolatedServices.getFilterService());
stmtSpi.getStatementContext().setSchedulingService(unisolatedServices.getSchedulingService());
stmtSpi.getStatementContext().setInternalEventEngineRouteDest(unisolatedServices.getInternalEventEngineRouteDest());
stmtSpi.getStatementContext().getScheduleAdjustmentService().adjust(delta);
statementNames.remove(stmtSpi.getName());
stmtSpi.setServiceIsolated(null);
applyFilterVersion(stmtSpi, unisolatedServices.getFilterService().getFiltersVersion());
}
// commit txn
unisolatedServices.getStatementIsolationService().commitUnisolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
} catch (EPServiceIsolationException ex) {
throw ex;
} catch (RuntimeException ex) {
unisolatedServices.getStatementIsolationService().rollbackUnisolatingStatements(isolatedServiceName, services.getUnitId(), stmt);
String message = "Unexpected exception taking statements: " + ex.getMessage();
log.error(message, ex);
throw new EPException(message, ex);
} finally {
unisolatedServices.getEventProcessingRWLock().releaseWriteLock();
}
}
/**
* Remove all statements from isolated services, such as upon destroy.
*/
public void removeAllStatements() {
List<EPStatement> statements = new ArrayList<EPStatement>();
for (String stmtName : statementNames) {
EPStatement stmt = unisolatedServices.getStatementLifecycleSvc().getStatementByName(stmtName);
if (stmt == null) {
log.debug("Statement '" + stmtName + "', the statement could not be found");
continue;
}
if (stmt.getServiceIsolated() != null && (!stmt.getServiceIsolated().equals(isolatedServiceName))) {
log.error("Error returning statement '" + stmtName + "', the internal isolation information is incorrect, isolated service for statement is currently '" +
stmt.getServiceIsolated() + "' and mismatches this isolated services named '" + isolatedServiceName + "'");
continue;
}
statements.add(stmt);
}
removeStatement(statements.toArray(new EPStatement[statements.size()]));
}
private void applyFilterVersion(EPStatementSPI stmtSpi, long filtersVersion) {
StatementResourceService resources = stmtSpi.getStatementContext().getStatementExtensionServicesContext().getStmtResources();
if (resources.getUnpartitioned() != null) {
applyFilterVersion(resources.getUnpartitioned(), filtersVersion);
} else {
for (Map.Entry<Integer, StatementResourceHolder> entry : resources.getResourcesPartitioned().entrySet()) {
applyFilterVersion(entry.getValue(), filtersVersion);
}
}
}
private void applyFilterVersion(StatementResourceHolder holder, long filtersVersion) {
holder.getAgentInstanceContext().getEpStatementAgentInstanceHandle().getStatementFilterVersion().setStmtFilterVersion(filtersVersion);
}
}