SpeedoQLQueryFilterVisitor.java :  » Database-ORM » Speedo_1.4.5 » org » objectweb » speedo » query » jdo » parser » Java Open Source

Java Open Source » Database ORM » Speedo_1.4.5 
Speedo_1.4.5 » org » objectweb » speedo » query » jdo » parser » SpeedoQLQueryFilterVisitor.java
/**
 * 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();
      }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.