/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S. Chassande-Barrioz
*
*/
package org.objectweb.speedo.query.jdo.parser;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.jorm.type.api.PType;
import org.objectweb.medor.api.Field;
import org.objectweb.medor.expression.api.Expression;
import org.objectweb.medor.expression.api.Operator;
import org.objectweb.medor.expression.api.ParameterOperand;
import org.objectweb.medor.expression.api.TypingException;
import org.objectweb.medor.expression.lib.And;
import org.objectweb.medor.expression.lib.BasicOperand;
import org.objectweb.medor.expression.lib.BasicParameterOperand;
import org.objectweb.medor.expression.lib.Bitwize;
import org.objectweb.medor.expression.lib.ConditionalAnd;
import org.objectweb.medor.expression.lib.ConditionalOr;
import org.objectweb.medor.expression.lib.DivideBy;
import org.objectweb.medor.expression.lib.Equal;
import org.objectweb.medor.expression.lib.Greater;
import org.objectweb.medor.expression.lib.GreaterEqual;
import org.objectweb.medor.expression.lib.Length;
import org.objectweb.medor.expression.lib.Like;
import org.objectweb.medor.expression.lib.Lower;
import org.objectweb.medor.expression.lib.LowerEqual;
import org.objectweb.medor.expression.lib.Minus;
import org.objectweb.medor.expression.lib.Mult;
import org.objectweb.medor.expression.lib.Not;
import org.objectweb.medor.expression.lib.NotEqual;
import org.objectweb.medor.expression.lib.Or;
import org.objectweb.medor.expression.lib.Plus;
import org.objectweb.medor.expression.lib.StringComparatorParameterOperand;
import org.objectweb.medor.expression.lib.StringLower;
import org.objectweb.medor.expression.lib.StringUpper;
import org.objectweb.medor.expression.lib.UMinus;
import org.objectweb.medor.expression.lib.Substring;
import org.objectweb.medor.filter.lib.BasicFieldOperand;
import org.objectweb.medor.filter.lib.ExpressionPrinter;
import org.objectweb.medor.filter.lib.InCollection;
import org.objectweb.medor.filter.lib.IsEmpty;
import org.objectweb.medor.filter.lib.IsNull;
import org.objectweb.medor.filter.lib.MemberOf;
import org.objectweb.medor.query.api.QueryTree;
import org.objectweb.medor.query.api.QueryTreeField;
import org.objectweb.medor.query.jorm.lib.QueryBuilder;
import org.objectweb.medor.query.lib.SelectProject;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.mapper.api.JormFactory;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import javax.jdo.JDOException;
import java.util.Collections;
import java.util.Map;
import java.util.Stack;
/**
* Implementation of a visitor that creates the filter
*/
public class SpeedoQLQueryFilterVisitor extends SpeedoQLAbstractVisitor {
private final static String CONTAINS_PATH_SET = "Next element is the contain path set";
private final static String REMOVER = "Remover";
/**
* qf is the transformation of the filter into a MEDOR expression
*/
private Expression qf = null;
/**
* qt is built by the SpeedoQLVariableVisitor and is just used here
*/
private QueryTree qt = null;
private SelectProject root;
/**
* speedoql is the result of the filter parsing
*/
private ASTSpeedoQL speedoql = null;
Map fields;
QueryBuilder qb;
private int nbNot = 0;
private String tab ="";
private JormFactory jf = null;
private Class clazz = null;
public SpeedoQLQueryFilterVisitor(Map _fields,
SelectProject _root,
ASTSpeedoQL speedoql,
Logger logger,
Map hparam,
Map vparam,
Class clazz,
QueryBuilder _qb,
JormFactory jf) throws SpeedoException {
//qt = qtree;
this.fields = _fields;
this.speedoql = speedoql;
this.qt = _root;
this.root = _root;
this.qb = _qb;
this.jf = jf;
setLogger(logger);
setParams(hparam);
setVars(vparam);
setCurrentClass(clazz.getName());
this.clazz = clazz;
startVisiting();
}
/**
* the visit starts here, please before sets a list of variables.
* @throws java.lang.Exception
*/
public void startVisiting() throws SpeedoException {
debug = logger.isLoggable(BasicLevel.DEBUG);
nbNot = 0;
try {
visit(speedoql);
} catch (Exception e) {
if (e instanceof SpeedoQLAbstractVisitor.VisitorException) {
e = ((SpeedoQLAbstractVisitor.VisitorException) e).getNestedException();
}
throw new SpeedoException(
"Impossible to built the queryTree during the filter visit", e);
}
// this expression is the filter of the SelectProject
Expression exprFilter = getQueryFilter();
if (exprFilter != null) {
ME me = replaceNullNode(exprFilter);
if (me != null && me.modified) {
qf = me.e;
exprFilter = getQueryFilter();
}
if (debug) {
logger.log(BasicLevel.DEBUG, "filter = " + exprFilter.getClass().getName());
}
root.setQueryFilter(exprFilter);
}
}
private static class ME {
public Expression e;
public boolean modified;
public ME(Expression _e) {
this.e = _e;
this.modified = true;
}
}
/**
* Replace null node.
* @param exprFilter
*/
private ME replaceNullNode(Expression exprFilter) throws SpeedoException {
ME me = null;
if ((exprFilter instanceof Equal) || (exprFilter instanceof NotEqual)){
Operator op = (Operator) exprFilter;
for (int i = 0; i < op.getOperandNumber(); i++) {
if (op.getExpression(i) instanceof DummyOperand) {
//get the other child operand
int j = (i+1) % 2;
Expression other = op.getExpression(j);
PType ptype = other.getType();
if (ptype.getTypeCode() == PType.TYPECODE_REFERENCE) {
PName val = null;
try {
val = jf.getPClassMapping(ptype.getJormName(), clazz.getClassLoader()).getPBinder().getNull();
} catch (Exception e) {
throw new SpeedoException(
"Try to replace null node. Impossible to find the null PName for the type " + ptype.getJormName(), e);
}
//replace the null node with null PName
op.setExpression(i, new BasicOperand(val, ptype));
} else {
//Transform the null [not]equality into a IsNull operator
me = new ME(new IsNull(other, exprFilter instanceof NotEqual));
//recursion is done on the other operand
exprFilter = me.e;
}
}
}
}
if (exprFilter instanceof Operator) {
Operator op = (Operator) exprFilter;
for (int i = 0; i < op.getOperandNumber(); i++) {
//recursivity
ME ime = replaceNullNode(op.getExpression(i));
if (ime != null && ime.modified) {
//replace the child
op.setExpression(i, ime.e);
//mark the result as modified
if (me == null) {//create if not already done
me = new ME(exprFilter);
}
me.modified = true;
}
}
}
return me; //can be null
}
/**
* get the query filter that was built from visiting the syntaxic tree
*/
public Expression getQueryFilter() {
return qf;
}
public Object visit(ASTPrimary node, Object data) {
Stack stack = (Stack) data;
boolean hasMethod = node.value != null;
if (hasMethod) {
stack.push(node.value);
}
visit((SimpleNode) node, data);
if (hasMethod) {
Expression e2 = (Expression) stack.pop();
Expression e1 = (Expression) stack.pop();
String methodName = (String) stack.pop();
if (methodName.startsWith("null.")) {
methodName = methodName.substring("null.".length());
}
stack.push(e1);
stack.push(methodName);
e1 = treatMethodOperator(methodName, stack, e2);
if (e1 != null) {
stack.push(e1);
}
}
return null;
}
public Object visit(ASTSpeedoPrimary node, Object data) {
visit((SimpleNode) node, data);
Stack stack = (Stack) data;
while(stack.size() >0 && REMOVER.equals(stack.peek())) {
stack.pop();
}
if (stack.size() >0) {
qf = (Expression) stack.pop();
} // else there is no filter
return null;
}
/**
*
*/
public Object visit(ASTRelationalExpression node, Object data) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Visit RelationalExpression: " + node);
}
tab += '\t';
visit((SimpleNode) node, data);
tab = tab.substring(1);
Stack stack = (Stack) data;
if (stack.size() > 0) {
if (CONTAINS_PATH_SET.equals(stack.peek())) {
if (debug) {
logger.log(BasicLevel.ERROR, "remove the element of the stack");
}
} else {
if (debug) {
logger.log(BasicLevel.DEBUG, "manage relational expression: "
+ "(children: " + node.jjtGetNumChildren()
+ ", stack: " + stack.size()
+ ", peek:" + stack.peek() + ")");
}
for (int i = 0; (i < (node.jjtGetNumChildren() - 1) && stack.size() > 0); i++) {
int op = ((Integer) node.ops.get(node.jjtGetNumChildren() - 2 - i)).intValue();
if (usedInRelationalExpresssion(op)) {
Object child2 = stack.pop();
Object child1 = stack.pop();
if (debug) {
logger.log(BasicLevel.DEBUG, "pop child1: " + child1);
logger.log(BasicLevel.DEBUG, "pop child2: " + child2);
}
if (REMOVER.equals(child1)) {
if (REMOVER.equals(child2)) {
//nothin
} else {
stack.push(child2);
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + child2 + ")");
}
}
} else {
if (REMOVER.equals(child2)) {
stack.push(child1);
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + child1 + ")");
}
} else {
Expression ret = null;
switch (op) {
case SpeedoQLConstants.OR:
ret = new ConditionalOr((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.AND:
ret = new ConditionalAnd((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.BITWISEOR:
ret = new Or((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.BITWISEXOR:
ret = null;
break;
case SpeedoQLConstants.BITWISEAND:
ret = new And((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.EQ:
ret = new Equal((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.NEQ:
ret = new NotEqual((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.LT:
ret = new Lower((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.GT:
ret = new Greater((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.GTE:
ret = new GreaterEqual((Expression) child1, (Expression) child2);
break;
case SpeedoQLConstants.LTE:
ret = new LowerEqual((Expression) child1, (Expression) child2);
break;
}
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + ret + ")");
}
stack.push(ret);
}
}
}
}
}
}
if (debug) {
logger.log(BasicLevel.DEBUG, "children:" + node.jjtGetNumChildren()
+ " / stack: " + stack.size());
logger.log(BasicLevel.DEBUG, tab + "End of Visit RelationalExpression: " + node);
}
return null;
}
private boolean usedInRelationalExpresssion(int op) {
switch (op) {
case SpeedoQLConstants.OR:
case SpeedoQLConstants.AND:
case SpeedoQLConstants.BITWISEOR:
case SpeedoQLConstants.BITWISEXOR:
case SpeedoQLConstants.BITWISEAND:
case SpeedoQLConstants.EQ:
case SpeedoQLConstants.NEQ:
case SpeedoQLConstants.LT:
case SpeedoQLConstants.GT:
case SpeedoQLConstants.GTE:
case SpeedoQLConstants.LTE:
if (debug) {
logger.log(BasicLevel.DEBUG, "node useful");
}
return true;
default:
if (debug) {
logger.log(BasicLevel.DEBUG, "node useless");
}
return false;
}
}
public Object visit(ASTAdditiveExpression node, Object data) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Visit AdditiveExpression: " + node);
}
tab += '\t';
visit((SimpleNode) node, data);
tab = tab.substring(1);
Stack stack = (Stack) data;
if (stack.size() > 0
&& !CONTAINS_PATH_SET.equals(stack.peek())
&& !REMOVER.equals(stack.peek())) {
Expression ret = (Expression) stack.pop();
for (int i = 0; i < node.jjtGetNumChildren() - 1; i++) {
if (debug) {
logger.log(BasicLevel.DEBUG, "Visit ConditionalExpression... children...[" + i + "]");
}
switch (((Integer) node.ops.get(node.jjtGetNumChildren() - 2 - i)).intValue()) {
case SpeedoQLConstants.PLUS:
ret = new Plus((Expression) stack.pop(), ret);
break;
case SpeedoQLConstants.MINUS:
ret = new Minus((Expression) stack.pop(), ret);
break;
case SpeedoQLConstants.MULT:
ret = new Mult((Expression) stack.pop(), ret);
break;
case SpeedoQLConstants.DIV:
ret = new DivideBy((Expression) stack.pop(), ret);
break;
default:
}
}
((Stack) data).push(ret);
}
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "End of Visit AdditiveExpression: " + node);
}
return null;
}
public Object visit(ASTUnaryExpression node, Object data) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Visit UnaryExpression" + node);
}
tab += '\t';
boolean hasNot = node.ops.size() > 0
&& ((Integer) node.ops.get(0)).intValue() == SpeedoQLConstants.NOT;
if (hasNot) {
nbNot ++;
if (debug) {
logger.log(BasicLevel.DEBUG, "remember a Not: "+ nbNot);
}
}
visit((SimpleNode) node, data);
if (hasNot && nbNot> 0) {
nbNot--;
if (debug) {
logger.log(BasicLevel.DEBUG, "forget a Not: "+ nbNot);
}
}
tab = tab.substring(1);
Stack stack = (Stack) data;
if (debug && stack.size() > 0) {
logger.log(BasicLevel.DEBUG, tab + "stack.peek:" + stack.peek());
}
if (stack.size() > 0
&& !CONTAINS_PATH_SET.equals(stack.peek())
&& !REMOVER.equals(stack.peek())) {
Object o = stack.pop();
if (node.ops.size() > 0) {
switch (((Integer) node.ops.get(0)).intValue()) {
case SpeedoQLConstants.MINUS:
o = new UMinus((Expression) o);
break;
case SpeedoQLConstants.BITWISECOMPL:
o = new Bitwize((Expression) o);
break;
case SpeedoQLConstants.NOT:
logger.log(BasicLevel.DEBUG, "NOT(" + o + "): " + node);
o = new Not((Expression) o);
break;
}
}
((Stack) data).push(o);
}
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "End of Visit UnaryExpression: " + node);
}
return null;
}
// to be done
public Object visit(ASTCastExpression node, Object data) {
((Stack) data).push(node);
return null;
}
/**
* 4 cases to manage: (en cours par equipe MEDOR)
* - Collection.contains(Object o)
* - Collection.isEmpty()
* - String.startsWith(String s)
* - String.endsWith(String s)
*/
public Object visit(ASTArgumentList node, Object data) {
visit((SimpleNode) node, data);
return null;
}
public Object visit(ASTLiteral node, Object data) {
Stack stack = (Stack) data;
Expression e = null;
if (node.value == null) {
//special case for null: will be replaced later
e = new DummyOperand();
} else if (node.value instanceof Integer) {
e = new BasicOperand(((Integer) node.value).intValue());
} else if (node.value instanceof Float) {
e = new BasicOperand(((Float) node.value).floatValue());
} else if (node.value instanceof Character) {
e = new BasicOperand(((Character) node.value).charValue());
} else if (node.value instanceof String) {
String s = (String) (node.value);
s = s.substring(1, s.length()-1);
e = new BasicOperand(s);
} else if (node.value instanceof Boolean) {
e = new BasicOperand(((Boolean) node.value).booleanValue());
}
if (stack.size() > 0) {
Object top = stack.peek();
if (CONTAINS_PATH_SET.equals(top)) {
//TODO: Support the path.contains(path) operator
logger.log(BasicLevel.ERROR, "The path.contains(path) operator is not yet implemented");
return null;
} else if (top instanceof String) {
e = treatMethodOperator((String) top, stack, e);
}
}
if (e != null) {
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + ExpressionPrinter.e2str(e) + ")");
}
stack.push(e);
}
return null;
}
private Expression treatMethodOperator(String opName,
Stack stack,
Expression e) {
int op = isMethodOperator(opName);
if (op == -1) {
return e;
}
switch (op) {
case STARTS_WITH_OPERATOR:
{
stack.pop();
Object oe = stack.pop();
if (debug) {
logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
}
Expression str = (Expression) oe;
if (e instanceof BasicParameterOperand) {
e = new StringComparatorParameterOperand((BasicParameterOperand) e, null, ".*");
} else if (e instanceof BasicOperand) {
try {
e = new BasicOperand(((BasicOperand) e).getString() + ".*");
} catch (TypingException e1) {
throw new JDOException(
"Bad parameter type for the 'startsWith' method", e1);
}
}
e = new Like(str, e);
break;
}
case ENDS_WITH_OPERATOR:
{
stack.pop();
Object oe = stack.pop();
if (debug) {
logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
}
Expression str = (Expression) oe;
if (e instanceof BasicParameterOperand) {
e = new StringComparatorParameterOperand((BasicParameterOperand) e, ".*", null);
} else if (e instanceof BasicOperand) {
try {
e = new BasicOperand("%" + ((BasicOperand) e).getString());
} catch (TypingException e1) {
throw new JDOException(
"Bad parameter type for the 'startsWith' method", e1);
}
}
e = new Like(str, e);
break;
}
case EQUALS_OPERATOR:
//TODO: Support the equals operator
break;
case MATCHES_OPERATOR:
{
stack.pop();
Object oe = stack.pop();
if (debug) {
logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
}
Expression str = (Expression) oe;
if (e instanceof BasicParameterOperand) {
//e = new StringComparatorParameterOperand((BasicParameterOperand) e, "%", "%");
} else if (e instanceof BasicOperand) {
try {
e = new BasicOperand(((BasicOperand) e).getString());
} catch (TypingException e1) {
throw new JDOException(
"Bad parameter type for the 'startsWith' method", e1);
}
}
e = new Like(str, e);
break;
}
case SUBSTRING_OPERATOR:
{
stack.pop();
Object o = stack.pop();
if (o == STR_OPERAND_SUBSTRING) {
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + ExpressionPrinter.e2str(e) + ")");
}
stack.push(e);
if (debug) {
logger.log(BasicLevel.DEBUG, "push(BEGIN_OPERAND_SUBSTRING)");
}
stack.push(BEGIN_OPERAND_SUBSTRING);
if (debug) {
logger.log(BasicLevel.DEBUG, "push(" + opName + ")");
}
stack.push(opName);
return null;
} else if (o == BEGIN_OPERAND_SUBSTRING) {
Expression begin = (Expression) stack.pop();
Expression str = (Expression) stack.pop();
e = new Substring(str, begin, e);
} else {
throw new JDOException("Protocol error: " + o);
}
break;
}
}
return e;
}
public Object visit(ASTType node, Object data) {
if (debug) {
logger.log(BasicLevel.DEBUG, "Visit Type: " + node);
}
((Stack) data).push(node);
if (debug) {
logger.log(BasicLevel.DEBUG, "End of Visit Type");
}
return null;
}
/**
* qualifiedname could be:
* - a class field (salary from Employee)
* - a parameter
* - a variable
*
*/
public Object visit(ASTQualifiedName node, Object data) {
String name = (String) node.value;
String[] splitted = splitPath(name);
Stack stack = (Stack) data;
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Visit QualifiedName value=["
+ node.value + "] stack size=" + stack.size());
}
try {
if (params != null && params.get(splitted[0]) != null) {
visitParameter(stack, splitted, name);
} else {
if (!"this".equals(splitted[0])
&& (vars == null || vars.get(splitted[0]) == null)) {
//It is not a variable, but a navigation from the current
// class without 'this' at the begin. then add the
// class name in first
name = "this." + name;
String[] newsplitted = new String[splitted.length + 1];
newsplitted[0] = "this";
System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
splitted = newsplitted;
}
visitFieldAccess(stack, splitted, name);
}
} catch (Exception e) {
throw new SpeedoQLAbstractVisitor.VisitorException(e);
}
return null;
}
private void visitParameter(Stack stack,
String[] splitted,
String name) throws Exception {
if (stack.size() > 0 && CONTAINS_PATH_SET.equals(stack.peek())) {
//x.y.bs.contains(myParam)
stack.pop(); // forget the CONTAINS_PATH_SET
Object o = stack.pop(); // pop the pathset
String pathset = (String) o;
if (debug) {
logger.log(BasicLevel.DEBUG, tab
+ "parameter(" + name + ") MemberOf " + pathset);
}
String[] spli = splitPath(pathset);
String rest = mergePath(spli, 1, spli.length - 1);
QueryBuilder subquery = new QueryBuilder(qb);
subquery.define("", qb.navigate(spli[0]));
QueryTreeField setField = subquery.project(subquery.navigate(rest));
Expression e = new MemberOf(
Collections.singletonList(((Object[]) params.get(name))[1]),
Collections.singletonList(new BasicFieldOperand(setField)));
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "push(" + ExpressionPrinter.e2str(e) + ")");
}
stack.push(e);
} else if (splitted.length == 1) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Push the parameterOperand " + name);
}
Expression e = (Expression) ((Object[]) params.get(name))[1];
if (stack.size() > 0 && stack.peek() instanceof String) {
e = treatMethodOperator((String) stack.peek(), stack, e);
}
stack.push(e);
} else if (splitted.length == 2 && "contains".equals(splitted[1])) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Push the parameterOperand " + splitted[0]);
}
ParameterOperand po = (ParameterOperand)
((Object[]) params.get(splitted[0]))[1];
stack.push(po);
stack.push(CONTAINS_PATH_SET);
} else {
throw new Exception("Does not support the naviation over a parameter: " + name);
}
}
private void visitFieldAccess(Stack stack,
String[] splitted,
String name) throws Exception {
int operatorId = -1;
if (stack.size() > 0 && CONTAINS_PATH_SET.equals(stack.peek())) {
stack.pop(); // forget the CONTAINS_PATH_SET
Object o = stack.pop(); // pop the pathset
if (o instanceof ParameterOperand) {
//myParam.contains(...)
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "(" + name + ") InCollection (" + o + ")");
}
Field qtf = (Field) fields.get(name);
Expression e = new InCollection(
new BasicFieldOperand(qtf),
(ParameterOperand) o, qtf.getType());
stack.push(e);
} else if (o instanceof String) {
String pathset = (String) o;
String[] spli = splitPath(pathset);
if (vars.containsKey(splitted[0])) {
//x.y.bs.contains(b)
//The variable definition is managed by the Variable visitor
//thus forget the expression
if ((nbNot % 2) == 0) {
stack.push(REMOVER);
} else {
QueryTreeField f = (QueryTreeField) fields.get(name);
stack.push(new Not(new IsEmpty(new BasicFieldOperand(f))));
}
} else {
//x.y.bs.contains(u.v.b)
String rest = mergePath(spli, 1, spli.length - 2);
QueryBuilder subquery = new QueryBuilder(qb);
subquery.define("", qb.navigate(spli[0]));
QueryTreeField setField = subquery.project(subquery.navigate(rest));
QueryTreeField f = (QueryTreeField) fields.get(name);
stack.push(new MemberOf(
Collections.singletonList(
new BasicFieldOperand(f)),
Collections.singletonList(
new BasicFieldOperand(setField))
));
}
} else {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Do not use the pathset of the contain operator");
}
stack.push(REMOVER);
}
return;
}
//maybe there is an operator
String last = splitted[splitted.length - 1];
operatorId = isMethodOperator(last);
if (operatorId == -1) {
//No operator found ==> default case
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "create a fieldOperand with:" + name);
}
Field f = (Field) fields.get(name);
if (f == null) {
throw new SpeedoException("Internal error: No field '" + name + "' found during filter parsing");
}
stack.push(new BasicFieldOperand(f));
return;
}
//There is an operator
String begin = buildStringwithout(splitted, splitted.length-1, ".");
if (operatorId == CONTAINS_OPERATOR) {
//The contains contraint is managed during the QueryTree creation
//see the variable vistor
//However push some stuff in the stack in order to known that
// the next qualifiedName is used in a contain constraint.
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "contains operator: set=" + begin);
}
stack.push(begin);
stack.push(CONTAINS_PATH_SET);
return;
} else if (operatorId == IS_EMPTY_OPERATOR) {
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "Visit IsEmpty: " + begin);
}
String rest = mergePath(splitted, 1, splitted.length - 2);
QueryBuilder subquery = new QueryBuilder(qb);
subquery.define("", qb.navigate(splitted[0]));
Field f = subquery.project(subquery.navigate(rest));
stack.push(new IsEmpty(new BasicFieldOperand(f)));
return;
}
if (debug) {
logger.log(BasicLevel.DEBUG, tab + "create a fieldOperand with:" + begin);
}
Field f = (Field) fields.get(begin);
Expression e = new BasicFieldOperand(f);
switch (operatorId) {
case TO_LOWER_OPERATOR:
e = new StringLower(e);
stack.push(e);
break;
case TO_UPPER_OPERATOR:
e = new StringUpper(e);
stack.push(e);
break;
case LENGTH_OPERATOR:
e = new Length(e);
stack.push(e);
break;
case SUBSTRING_OPERATOR:
stack.push(e);
stack.push(STR_OPERAND_SUBSTRING);
stack.push(last);
break;
default:
stack.push(e);
stack.push(last);
break;
}
}
static class DummyOperand extends BasicOperand {
public DummyOperand(){
super();
}
}
}