stream.expressions.ExpressionReader Maven / Gradle / Ivy
/*
* streams library
*
* Copyright (C) 2011-2014 by Christian Bockermann, Hendrik Blom
*
* streams is a library, API and runtime environment for processing high
* volume data streams. It is composed of three submodules "stream-api",
* "stream-core" and "stream-runtime".
*
* The streams library (and its submodules) is free software: you can
* redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* The stream.ai library (and its submodules) is distributed in the hope
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package stream.expressions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExpressionReader {
int pos = 0;
String input;
Set supportedOperators = new HashSet();
Set supportedBoolOperators = new HashSet();
Set supportedVariables = null;
public final static boolean STRICT_PARSING = "true".equalsIgnoreCase(""
+ System.getProperty("event.filter.strict"));
static Logger log = LoggerFactory.getLogger(ExpressionReader.class);
boolean strictParsing = STRICT_PARSING;
protected ExpressionReader(String str) {
input = str;
pos = 0;
supportedBoolOperators.add(BooleanOperator.AND);
supportedBoolOperators.add(BooleanOperator.OR);
for (Operator op : Operator.OPERATORS.values())
supportedOperators.add(op);
}
protected ExpressionReader(String str, Collection variables) {
this(str);
supportedVariables = new HashSet();
for (String var : variables)
supportedVariables.add(var.toUpperCase());
}
protected ExpressionReader(String str, Collection variables,
Set operators) {
this(str, variables);
supportedOperators.clear();
supportedOperators.addAll(operators);
}
/**
* @return the strictParsing
*/
public boolean isStrictParsing() {
return strictParsing;
}
/**
* @param strictParsing
* the strictParsing to set
*/
public void setStrictParsing(boolean strictParsing) {
this.strictParsing = strictParsing;
}
public void setBooleanOperators(Set booleanOps) {
supportedBoolOperators = new HashSet(booleanOps);
}
public Set getBooleanOperators() {
return supportedBoolOperators;
}
protected Expression readFilterExpression() throws ExpressionException {
skipWhiteSpace();
Expression first;
if (startsWith("("))
first = readNestedExpression();
else
first = readSimpleFilter();
if (!endOfLine() && !hasBooleanOperator() && !startsWith(")"))
throw new ExpressionException(
"Boolean operator 'AND' or 'OR' expected after '"
+ input.substring(0, pos) + "'!");
if (endOfLine())
return first;
log.debug("remainder: {}", this.input.substring(pos));
List exps = new ArrayList();
List ops = new ArrayList();
exps.add(first);
while (!endOfLine() && hasBooleanOperator()) {
ops.add(readBooleanOperator());
if (startsWith("("))
exps.add(readNestedExpression());
else
exps.add(readSimpleFilter());
}
log.debug("Ops: {}", ops);
log.debug("Exps: {}", exps);
if (exps.size() == 1)
return first;
return new ExpressionList(ops.iterator().next(), exps);
}
public boolean endOfLine() {
return pos >= input.length() || input.substring(pos).trim().equals("");
}
public ExpressionList readNestedExpression() throws ExpressionException {
if (!startsWith("("))
throw new ExpressionException(
"No start of nested expression found!");
skipWhiteSpace();
pos++;
Collection exp = new ArrayList();
exp.add(readFilterExpression());
BooleanOperator op = BooleanOperator.AND;
while (!startsWith(")")) {
if (endOfLine())
throw new ExpressionException(
"Unexpected end of expression! Missing a closing bracket?");
op = readBooleanOperator();
if (startsWith("("))
exp.add(readNestedExpression());
else
exp.add(readFilterExpression());
}
this.skipWhiteSpace();
pos++; // <-- consume closing bracket?
return new ExpressionList(op, exp);
}
public boolean startsWith(String str) {
int i = pos;
while (i < input.length() && Character.isWhitespace(input.charAt(i)))
i++;
if (i >= input.length())
return false;
return input.substring(i).startsWith(str);
}
public Expression readSimpleFilter() throws ExpressionException {
try {
String left = readVariable();
Operator op = readOperator();
String right = readValue();
return new Match(left, op, right);
} catch (ExpressionException se) {
throw new ExpressionException(se.getMessage());
}
}
protected boolean hasBooleanOperator() {
int i = pos;
while (i < input.length() && Character.isWhitespace(input.charAt(i)))
i++;
if (i >= input.length())
return false;
String rest = input.substring(i);
return rest.toLowerCase().startsWith("or ")
|| rest.toLowerCase().startsWith("and ");
}
protected BooleanOperator readBooleanOperator() throws ExpressionException {
skipWhiteSpace();
StringBuffer var = new StringBuffer();
skipWhiteSpace();
while (pos < input.length()
&& !Character.isWhitespace(input.charAt(pos)))
var.append(input.charAt(pos++));
String operatorName = var.toString();
BooleanOperator op = BooleanOperator.read(operatorName);
if (!supportedBoolOperators.contains(op)) {
if (this.isStrictParsing())
throw new ExpressionException("Boolean operator '"
+ operatorName + "' is not supported!");
else
log.warn(
"Boolean operator '{}' is not supported, but 'strictParsing' is disabled!",
operatorName);
}
return op;
}
public int getPosition() {
return pos;
}
public String getInputString() {
return input;
}
protected void skipWhiteSpace() {
while (pos < input.length()
&& Character.isWhitespace(input.charAt(pos)))
pos++;
}
protected String readVariable() throws ExpressionException {
StringBuffer var = new StringBuffer();
skipWhiteSpace();
while (pos < input.length()
&& !Character.isWhitespace(input.charAt(pos)))
var.append(input.charAt(pos++));
String variable = var.toString();
if (this.supportedVariables != null
&& !supportedVariables.contains(variable.toUpperCase())) {
if (isStrictParsing())
throw new ExpressionException("Not a valid variable name '"
+ variable + "'!");
else
log.warn(
"Found variable '{}' which has not been defined previously!",
variable);
}
return variable;
}
protected Operator readOperator() throws ExpressionException {
skipWhiteSpace();
if (pos >= input.length())
throw new ExpressionException("Operator expected at position "
+ pos + ", found: '" + input.substring(pos) + "'!");
StringBuffer buf = new StringBuffer();
while (pos < input.length()
&& !Character.isWhitespace(input.charAt(pos)))
buf.append(input.charAt(pos++));
//
// extract the appropriate operator, this will throw an exception
// if the operator name is not valid
//
Operator op = Operator.read(buf.toString());
if (!supportedOperators.contains(op)) {
if (isStrictParsing())
throw new ExpressionException("Operator '" + op.toString()
+ "' not supported!");
else
log.warn(
"Operator '{}' is not supported, but 'strictParsing' disabled!",
op);
}
return op;
}
protected String readValue() throws ExpressionException {
StringBuffer var = new StringBuffer();
skipWhiteSpace();
if (endOfLine() || startsWith(")") || hasBooleanOperator())
throw new ExpressionException("Value expected at position " + pos
+ "!");
if (input.charAt(pos) == '"' || input.charAt(pos) == '\'') {
return readQuotedString(input.charAt(pos));
}
while (pos < input.length() && input.charAt(pos) != ')'
&& !Character.isWhitespace(input.charAt(pos)))
var.append(input.charAt(pos++));
return var.toString();
}
protected String readQuotedString(char ch) {
StringBuffer s = new StringBuffer();
while (pos < input.length() && ch != input.charAt(pos)) {
pos++;
}
pos++;
if (pos < input.length())
s.append(input.charAt(pos++));
char last = ' ';
while (pos < input.length() && last != '\\' && ch != input.charAt(pos)) {
char cur = input.charAt(pos++);
s.append(cur);
last = cur;
}
pos++;
return s.toString();
}
public final static Expression parse(String str) throws ExpressionException {
log.debug("Parsing expression: {}", str);
ExpressionReader r = new ExpressionReader(str);
return r.readFilterExpression();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy