com.espertech.esper.core.deploy.EPLModuleUtil 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.EventType;
import com.espertech.esper.client.deploy.Module;
import com.espertech.esper.client.deploy.ModuleItem;
import com.espertech.esper.client.deploy.ParseException;
import com.espertech.esper.core.service.StatementEventTypeRef;
import com.espertech.esper.epl.core.engineimport.EngineImportService;
import com.espertech.esper.epl.generated.EsperEPL2GrammarLexer;
import com.espertech.esper.epl.generated.EsperEPL2GrammarParser;
import com.espertech.esper.epl.parse.CaseInsensitiveInputStream;
import com.espertech.esper.epl.parse.ParseHelper;
import com.espertech.esper.event.EventAdapterService;
import com.espertech.esper.event.EventTypeSPI;
import com.espertech.esper.filter.FilterService;
import org.antlr.v4.runtime.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;
public class EPLModuleUtil {
private final static Logger log = LoggerFactory.getLogger(EPLModuleUtil.class);
/**
* Newline character.
*/
public static final String NEWLINE = System.getProperty("line.separator");
public static Module readInternal(InputStream stream, String resourceName) throws IOException, ParseException {
BufferedReader br = new BufferedReader(new InputStreamReader(stream));
StringWriter buffer = new StringWriter();
String strLine;
while ((strLine = br.readLine()) != null) {
buffer.append(strLine);
buffer.append(NEWLINE);
}
stream.close();
return parseInternal(buffer.toString(), resourceName);
}
public static Module parseInternal(String buffer, String resourceName) throws IOException, ParseException {
List semicolonSegments = EPLModuleUtil.parse(buffer.toString());
List nodes = new ArrayList();
for (EPLModuleParseItem segment : semicolonSegments) {
nodes.add(EPLModuleUtil.getModule(segment, resourceName));
}
String moduleName = null;
int count = 0;
for (ParseNode node : nodes) {
if (node instanceof ParseNodeComment) {
continue;
}
if (node instanceof ParseNodeModule) {
if (moduleName != null) {
throw new ParseException("Duplicate use of the 'module' keyword for resource '" + resourceName + "'");
}
if (count > 0) {
throw new ParseException("The 'module' keyword must be the first declaration in the module file for resource '" + resourceName + "'");
}
moduleName = ((ParseNodeModule) node).getModuleName();
}
count++;
}
Set uses = new LinkedHashSet();
Set imports = new LinkedHashSet();
count = 0;
for (ParseNode node : nodes) {
if ((node instanceof ParseNodeComment) || (node instanceof ParseNodeModule)) {
continue;
}
String message = "The 'uses' and 'import' keywords must be the first declaration in the module file or follow the 'module' declaration";
if (node instanceof ParseNodeUses) {
if (count > 0) {
throw new ParseException(message);
}
uses.add(((ParseNodeUses) node).getUses());
continue;
}
if (node instanceof ParseNodeImport) {
if (count > 0) {
throw new ParseException(message);
}
imports.add(((ParseNodeImport) node).getImported());
continue;
}
count++;
}
List items = new ArrayList();
for (ParseNode node : nodes) {
if ((node instanceof ParseNodeComment) || (node instanceof ParseNodeExpression)) {
boolean isComments = node instanceof ParseNodeComment;
items.add(new ModuleItem(node.getItem().getExpression(), isComments, node.getItem().getLineNum(), node.getItem().getStartChar(), node.getItem().getEndChar()));
}
}
return new Module(moduleName, resourceName, uses, imports, items, buffer);
}
public static List undeployTypes(Set referencedTypes, StatementEventTypeRef statementEventTypeRef, EventAdapterService eventAdapterService, FilterService filterService) {
List undeployedTypes = new ArrayList();
for (String typeName : referencedTypes) {
boolean typeInUse = statementEventTypeRef.isInUse(typeName);
if (typeInUse) {
if (log.isDebugEnabled()) {
log.debug("Event type '" + typeName + "' is in use, not removing type");
}
continue;
}
if (log.isDebugEnabled()) {
log.debug("Event type '" + typeName + "' is no longer in use, removing type");
}
EventType type = eventAdapterService.getExistsTypeByName(typeName);
if (type != null) {
EventTypeSPI spi = (EventTypeSPI) type;
if (!spi.getMetadata().isApplicationPreConfigured()) {
eventAdapterService.removeType(typeName);
undeployedTypes.add(spi);
filterService.removeType(spi);
}
}
}
return undeployedTypes;
}
public static ParseNode getModule(EPLModuleParseItem item, String resourceName) throws ParseException, IOException {
CharStream input = new CaseInsensitiveInputStream(item.getExpression());
EsperEPL2GrammarLexer lex = ParseHelper.newLexer(input);
CommonTokenStream tokenStream = new CommonTokenStream(lex);
tokenStream.fill();
List tokens = tokenStream.getTokens();
int beginIndex = 0;
boolean isMeta = false;
boolean isModule = false;
boolean isUses = false;
boolean isExpression = false;
while (beginIndex < tokens.size()) {
Token t = (Token) tokens.get(beginIndex);
if (t.getType() == EsperEPL2GrammarParser.EOF) {
break;
}
if ((t.getType() == EsperEPL2GrammarParser.WS) ||
(t.getType() == EsperEPL2GrammarParser.SL_COMMENT) ||
(t.getType() == EsperEPL2GrammarParser.ML_COMMENT)) {
beginIndex++;
continue;
}
String tokenText = t.getText().trim().toLowerCase(Locale.ENGLISH);
if (tokenText.equals("module")) {
isModule = true;
isMeta = true;
} else if (tokenText.equals("uses")) {
isUses = true;
isMeta = true;
} else if (tokenText.equals("import")) {
isMeta = true;
} else {
isExpression = true;
break;
}
beginIndex++;
beginIndex++; // skip space
break;
}
if (isExpression) {
return new ParseNodeExpression(item);
}
if (!isMeta) {
return new ParseNodeComment(item);
}
// check meta tag (module, uses, import)
StringWriter buffer = new StringWriter();
for (int i = beginIndex; i < tokens.size(); i++) {
Token t = (Token) tokens.get(i);
if (t.getType() == EsperEPL2GrammarParser.EOF) {
break;
}
if ((t.getType() != EsperEPL2GrammarParser.IDENT) &&
(t.getType() != EsperEPL2GrammarParser.DOT) &&
(t.getType() != EsperEPL2GrammarParser.STAR) &&
(!t.getText().matches("[a-zA-Z]*"))) {
throw getMessage(isModule, isUses, resourceName, t.getType());
}
buffer.append(t.getText().trim());
}
String result = buffer.toString().trim();
if (result.length() == 0) {
throw getMessage(isModule, isUses, resourceName, -1);
}
if (isModule) {
return new ParseNodeModule(item, result);
} else if (isUses) {
return new ParseNodeUses(item, result);
}
return new ParseNodeImport(item, result);
}
private static ParseException getMessage(boolean module, boolean uses, String resourceName, int type) {
String message = "Keyword '";
if (module) {
message += "module";
} else if (uses) {
message += "uses";
} else {
message += "import";
}
message += "' must be followed by a name or package name (set of names separated by dots) for resource '" + resourceName + "'";
if (type != -1) {
String tokenName = EsperEPL2GrammarParser.getLexerTokenParaphrases().get(type);
if (tokenName == null) {
tokenName = EsperEPL2GrammarParser.getParserTokenParaphrases().get(type);
}
if (tokenName != null) {
message += ", unexpected reserved keyword " + tokenName + " was encountered as part of the name";
}
}
return new ParseException(message);
}
public static List parse(String module) throws ParseException {
CharStream input = new CaseInsensitiveInputStream(module);
EsperEPL2GrammarLexer lex = ParseHelper.newLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lex);
try {
tokens.fill();
} catch (RuntimeException ex) {
String message = "Unexpected exception recognizing module text";
if (ex instanceof LexerNoViableAltException) {
if (ParseHelper.hasControlCharacters(module)) {
message = "Unrecognized control characters found in text, failed to parse text";
} else {
message += ", recognition failed for " + ex.toString();
}
} else if (ex instanceof RecognitionException) {
RecognitionException recog = (RecognitionException) ex;
message += ", recognition failed for " + recog.toString();
} else if (ex.getMessage() != null) {
message += ": " + ex.getMessage();
}
message += " [" + module + "]";
log.error(message, ex);
throw new ParseException(message);
}
List statements = new ArrayList();
StringWriter current = new StringWriter();
Integer lineNum = null;
int charPosStart = 0;
int charPos = 0;
List tokenList = tokens.getTokens();
Set skippedSemicolonIndexes = getSkippedSemicolons(tokenList);
int index = -1;
// Call getTokens first before invoking tokens.size! ANTLR problem
for (Object token : tokenList) {
index++;
Token t = (Token) token;
boolean semi = t.getType() == EsperEPL2GrammarLexer.SEMI && !skippedSemicolonIndexes.contains(index);
if (semi) {
if (current.toString().trim().length() > 0) {
statements.add(new EPLModuleParseItem(current.toString().trim(), lineNum == null ? 0 : lineNum, charPosStart, charPos));
lineNum = null;
}
current = new StringWriter();
} else {
if ((lineNum == null) && (t.getType() != EsperEPL2GrammarParser.WS)) {
lineNum = t.getLine();
charPosStart = charPos;
}
if (t.getType() != EsperEPL2GrammarLexer.EOF) {
current.append(t.getText());
charPos += t.getText().length();
}
}
}
if (current.toString().trim().length() > 0) {
statements.add(new EPLModuleParseItem(current.toString().trim(), lineNum == null ? 0 : lineNum, 0, 0));
}
return statements;
}
public static Module readFile(File file) throws IOException, ParseException {
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
return EPLModuleUtil.readInternal(inputStream, file.getAbsolutePath());
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.debug("Error closing input stream", e);
}
}
}
}
public static Module readResource(String resource, EngineImportService engineImportService) throws IOException, ParseException {
String stripped = resource.startsWith("/") ? resource.substring(1) : resource;
InputStream stream = null;
ClassLoader classLoader = engineImportService.getClassLoader();
if (classLoader != null) {
stream = classLoader.getResourceAsStream(stripped);
}
if (stream == null) {
stream = EPDeploymentAdminImpl.class.getResourceAsStream(resource);
}
if (stream == null) {
stream = EPDeploymentAdminImpl.class.getClassLoader().getResourceAsStream(stripped);
}
if (stream == null) {
throw new IOException("Failed to find resource '" + resource + "' in classpath");
}
try {
return EPLModuleUtil.readInternal(stream, resource);
} finally {
try {
stream.close();
} catch (IOException e) {
log.debug("Error closing input stream", e);
}
}
}
/**
* Find expression declarations and skip semicolon content between square brackets for scripts
*/
private static Set getSkippedSemicolons(List tokens) {
Set result = null;
int index = -1;
for (Object token : tokens) {
index++;
Token t = (Token) token;
if (t.getType() == EsperEPL2GrammarParser.EXPRESSIONDECL) {
if (result == null) {
result = new HashSet();
}
getSkippedSemicolonsBetweenSquareBrackets(index, tokens, result);
}
}
return result == null ? Collections.emptySet() : result;
}
/**
* Find content between square brackets
*/
private static void getSkippedSemicolonsBetweenSquareBrackets(int index, List tokens, Set result) {
// Handle EPL expression "{text}" and script expression "[text]"
int indexFirstCurly = indexFirstToken(index, tokens, EsperEPL2GrammarParser.LCURLY);
int indexFirstSquare = indexFirstToken(index, tokens, EsperEPL2GrammarParser.LBRACK);
if (indexFirstSquare == -1) {
return;
}
if (indexFirstCurly != -1 && indexFirstCurly < indexFirstSquare) {
return;
}
int indexCloseSquare = findEndSquareBrackets(indexFirstSquare, tokens);
if (indexCloseSquare == -1) {
return;
}
int current = indexFirstSquare;
while (current < indexCloseSquare) {
Token t = tokens.get(current);
if (t.getType() == EsperEPL2GrammarParser.SEMI) {
result.add(current);
}
current++;
}
}
private static int findEndSquareBrackets(int startIndex, List tokens) {
int index = startIndex + 1;
int squareBracketDepth = 0;
while (index < tokens.size()) {
Token t = tokens.get(index);
if (t.getType() == EsperEPL2GrammarParser.RBRACK) {
if (squareBracketDepth == 0) {
return index;
}
squareBracketDepth--;
}
if (t.getType() == EsperEPL2GrammarParser.LBRACK) {
squareBracketDepth++;
}
index++;
}
return -1;
}
private static int indexFirstToken(int startIndex, List tokens, int tokenType) {
int index = startIndex;
while (index < tokens.size()) {
Token t = tokens.get(index);
if (t.getType() == tokenType) {
return index;
}
index++;
}
return -1;
}
}