com.sm.query.PredicateVisitorImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.sm.query.PredicateVisitorImpl.java

Source

/*
 *
 *
 * Copyright 2012-2015 Viant.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 *  use this file except in compliance with the License. You may obtain a copy of
 *  the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 *  License for the specific language governing permissions and limitations under
 *  the License.
 *
 */

package com.sm.query;

import com.sm.query.parser.PredicateBaseVisitor;
import com.sm.query.parser.PredicateLexer;
import com.sm.query.parser.PredicateParser;
import com.sm.query.utils.*;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.misc.NotNull;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import voldemort.utils.Pair;

import java.io.StringReader;
import java.util.*;

import static com.sm.query.utils.QueryUtils.findObjectId;

public class PredicateVisitorImpl extends PredicateBaseVisitor<Result> {
    private static final Log logger = LogFactory.getLog(PredicateVisitorImpl.class);

    private Map<String, FieldInfo> idMap = new HashMap<String, FieldInfo>();
    private Map<String, ClassInfo> classInfoMap = new HashMap<String, ClassInfo>();
    private String queryStr;
    private Object source;
    private ParserRuleContext tree;

    public PredicateVisitorImpl(String queryStr) {
        this.queryStr = queryStr;
        init();
    }

    public PredicateVisitorImpl(String queryStr, Object source) {
        this.queryStr = queryStr;
        this.source = source;
        init();
    }

    private void init() {
        try {
            if (queryStr == null || queryStr.length() == 0)
                return;
            PredicateLexer lexer = new PredicateLexer(new ANTLRInputStream(new StringReader(queryStr)));
            CommonTokenStream token = new CommonTokenStream(lexer);
            PredicateParser parser = new PredicateParser(token);
            parser.setBuildParseTree(true);
            tree = parser.script();
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            throw new QueryException(ex.getMessage(), ex);
        }
    }

    public boolean runPredicate(Object source) {
        try {
            if (source == null || queryStr == null || queryStr.length() == 0) {
                //logger.info("source is null or queryStr is empty");
                return true;
            }
            //assign source
            this.source = source;
            //ParseTreeWalker walker = new ParseTreeWalker();
            Result result = visit(tree);
            return (Boolean) result.getValue();
        } catch (Exception ex) {
            logger.error(ex.getMessage());
            throw new QueryException(ex.getMessage(), ex);
        }
    }

    public void setQueryStr(String queryStr) {
        this.queryStr = queryStr;
        init();
    }

    @Override
    public Result visitBooleans(@NotNull PredicateParser.BooleansContext ctx) {
        boolean value = Boolean.valueOf(ctx.getText());
        return new Result(value);
    }

    @Override
    public Result visitParenPredicate(@NotNull PredicateParser.ParenPredicateContext ctx) {
        return visit(ctx.predicate());
        //return visitChildren( ctx);
    }

    @Override
    public Result visitScript(@NotNull PredicateParser.ScriptContext ctx) {

        if (ctx.getChildCount() == 1) //empty query, just EOF
            return new Result(true);
        else
            return visit(ctx.predicate());

    }

    @Override
    public Result visitNotPredicate(@NotNull PredicateParser.NotPredicateContext ctx) {
        return new Result(!(Boolean) visit(ctx.predicate()).getValue());
    }

    @Override
    public Result visitExistExpr(PredicateParser.ExistExprContext ctx) {
        Result left = visit(ctx.objectField(0));
        Collection collection;
        if (left.getValue() instanceof Collection) {
            collection = ((Collection) left.getValue());
            if (ctx.objectField().size() > 1)
                collection = QueryUtils.collectObjectField(ctx.objectField(1).getText(), collection, idMap,
                        classInfoMap);
        } else
            throw new ObjectIdException("require collection type " + left.getValue().getClass().getName());
        //Result right = visit( ctx.expression());
        return new Result(QueryUtils.existInIt(collection, visit(ctx.expression())));
    }

    @Override
    public Result visitExistListOr(PredicateParser.ExistListOrContext ctx) {
        Result left = visit(ctx.objectField(0));
        Collection collection;
        for (int i = 0; i < ctx.expression().size(); i++) {
            //Iterator iterator;
            if (left.getValue() instanceof Collection) {
                collection = ((Collection) left.getValue());
                if (ctx.objectField().size() > 1)
                    collection = QueryUtils.collectObjectField(ctx.objectField(1).getText(), collection, idMap,
                            classInfoMap);
            } else
                throw new ObjectIdException("require collection type " + left.getValue().getClass().getName());
            //if one match, exit with true
            if (QueryUtils.existInIt(collection, visit(ctx.expression(i))))
                return new Result(true);
        }
        // all false
        return new Result(false);

    }

    @Override
    public Result visitExistListAnd(PredicateParser.ExistListAndContext ctx) {
        Result left = visit(ctx.objectField(0));
        Collection collection;
        for (int i = 0; i < ctx.expression().size(); i++) {
            if (left.getValue() instanceof Collection) {
                collection = ((Collection) left.getValue());
                if (ctx.objectField().size() > 1)
                    collection = QueryUtils.collectObjectField(ctx.objectField(1).getText(), collection, idMap,
                            classInfoMap);
            } else
                throw new ObjectIdException("require collection type " + left.getValue().getClass().getName());
            //for and, if one did not match, exit with false
            if (!QueryUtils.existInIt(collection, visit(ctx.expression(i))))
                return new Result(false);
        }
        // all true
        return new Result(true);

    }

    @Override
    public Result visitCountExpr(PredicateParser.CountExprContext ctx) {
        Result left = visit(ctx.objectField(0));
        Iterator iterator;
        if (left.getValue() instanceof Collection) {
            Collection collection = ((Collection) left.getValue());
            if (ctx.objectField().size() > 1)
                iterator = QueryUtils
                        .collectObjectField(ctx.objectField(1).getText(), collection, idMap, classInfoMap)
                        .iterator();
            else
                iterator = collection.iterator();
        } else
            throw new ObjectIdException("require collection type " + left.getValue().getClass().getName());
        Result right = visit(ctx.expression(0));
        int count = 0;
        while (iterator.hasNext()) {
            Result lt = null;
            Object obj = iterator.next();
            if (obj instanceof Collection) {
                Iterator inside = ((Collection) obj).iterator();
                while (inside.hasNext()) {
                    lt = new Result(inside.next());
                    if (QueryUtils.compare(lt, "=", right))
                        break;
                }
            } else
                lt = new Result(obj);
            if (QueryUtils.compare(lt, "=", right)) {
                count++;
            }
        }
        String op = ctx.comparisonOperator().getText();
        int c = Integer.valueOf((String) visit(ctx.expression(1)).getValue());
        if (QueryUtils.compare(new Result(count), op, new Result(c)))
            return new Result(true);
        else
            return new Result(false);
    }

    @Override
    public Result visitLowerExpr(PredicateParser.LowerExprContext ctx) {
        String left = ((String) visit(ctx.objectField()).getValue()).toLowerCase();
        String right = (String) visit(ctx.expression()).getValue();
        if (ctx.comparisonOperator().getText().equals("="))
            return new Result(left.equals(right));
        else
            return new Result(!left.equals(right));

    }

    @Override
    public Result visitUpperExpr(PredicateParser.UpperExprContext ctx) {
        String left = ((String) visit(ctx.objectField()).getValue()).toUpperCase();
        String right = (String) visit(ctx.expression()).getValue();
        if (ctx.comparisonOperator().getText().equals("="))
            return new Result(left.equals(right));
        else
            return new Result(!left.equals(right));
    }

    @Override
    public Result visitSubstrExpr(PredicateParser.SubstrExprContext ctx) {
        String left = ((String) visit(ctx.objectField()).getValue());
        int index = Integer.valueOf((String) visit(ctx.expression(0)).getValue());
        String right = (String) visit(ctx.expression(1)).getValue();
        if (ctx.comparisonOperator().getText().equals("="))
            return new Result(left.substring(index).equals(right));
        else
            return new Result(!left.substring(index).equals(right));

    }

    @Override
    public Result visitInComp(@NotNull PredicateParser.InCompContext ctx) {
        Result objectId = visit(ctx.objectField());
        List<Result> listExpr = new ArrayList<Result>();
        for (PredicateParser.ExpressionContext each : ctx.expression())
            listExpr.add(visit(each));
        boolean result = QueryUtils.isInList(objectId, listExpr);
        return new Result(result);
    }

    @Override
    public Result visitComparison(@NotNull PredicateParser.ComparisonContext ctx) {
        Result left = visit(ctx.objectField());
        Result right = visit(ctx.expression());
        String operator = ctx.comparisonOperator().getText();
        boolean result = QueryUtils.compare(left, operator, right);
        return new Result(result);

    }

    @Override
    public Result visitUnaryOperator(@NotNull PredicateParser.UnaryOperatorContext ctx) {
        return null;
    }

    @Override
    public Result visitStrings(@NotNull PredicateParser.StringsContext ctx) {
        String str = ctx.getText().substring(1, ctx.getText().length() - 1);
        return new Result(str);
    }

    @Override
    public Result visitLogicalOperator(@NotNull PredicateParser.LogicalOperatorContext ctx) {
        return null;
    }

    @Override
    public Result visitNormal(@NotNull PredicateParser.NormalContext ctx) {
        if (ctx.predicate().size() == 1)
            return visit(ctx.predicate(0));
        else {
            Result left = visit(ctx.predicate(0));
            // implement short cut to skip right side for left is false and AND return false
            if (ctx.logicalOperator().getText().equals("and") && !(Boolean) left.getValue())
                return left;
            else if (ctx.logicalOperator().getText().equals("or") && (Boolean) left.getValue())
                return left;
            //no short cut case, run through full evaluation
            Result right = visit(ctx.predicate(1));
            if (ctx.logicalOperator().getText().equals("and")) {
                return new Result((Boolean) left.getValue() && (Boolean) right.getValue());
            } else {
                return new Result((Boolean) left.getValue() || (Boolean) right.getValue());
            }
        }
    }

    //    @Override
    //    public Result visitBinaryOperator(@NotNull PredicateParser.BinaryOperatorContext ctx) {
    //        return null;
    //    }

    @Override
    public Result visitObjectField(@NotNull PredicateParser.ObjectFieldContext ctx) {
        //first is object, second is field
        Pair<Object, FieldInfo> pair = findObjectId(ctx.getText(), source, classInfoMap);
        idMap.put(ctx.getText(), pair.getSecond());
        try {
            if (pair.getFirst() == null)
                return new Result(null);
            else {
                Object object = pair.getSecond().getField().get(pair.getFirst());
                return new Result(object);
            }
        } catch (IllegalAccessException e) {
            throw new ObjectIdException(e.getMessage(), e);
        }
    }

    @Override
    public Result visitExpParen(@NotNull PredicateParser.ExpParenContext ctx) {
        return visit(ctx.expression());
    }

    //    @Override
    //    public Result visitComparisonOperator(@NotNull PredicateParser.ComparisonOperatorContext ctx) {
    //        return null;
    //    }

    @Override
    public Result visitNumbers(@NotNull PredicateParser.NumbersContext ctx) {
        return new Result(Result.Type.NUMBER, ctx.getText());
    }

    @Override
    public Result visitExpr(@NotNull PredicateParser.ExprContext ctx) {
        Result left = visit(ctx.expression(0));
        Result right = visit(ctx.expression(1));
        String binaryOperator = ctx.binaryOperator().getText();
        return QueryUtils.binaryOp(left, binaryOperator, right);
    }

    @Override
    public Result visitCheckNull(@NotNull PredicateParser.CheckNullContext ctx) {
        Result result = visit(ctx.objectField());
        if (result.getType() == Result.Type.NULL)
            return new Result(true);
        else
            return new Result(false);
    }

}