Package org.objectweb.speedo.query.jdo.parser

Source Code of org.objectweb.speedo.query.jdo.parser.SpeedoQLVariableVisitor

/**
* 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 java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.jdo.JDOUserException;

import org.objectweb.jorm.metainfo.api.Manager;
import org.objectweb.medor.api.Field;
import org.objectweb.medor.api.MedorException;
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.speedo.api.SpeedoException;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
* @author S.Chassande-Barrioz
*/
public class SpeedoQLVariableVisitor extends SpeedoQLAbstractVisitor {

    private HashSet testcontains = new HashSet();
    private HashSet isEmptys = new HashSet();

    /**
     * qt is the built QueryTree from the current object.
     */
    private QueryTree qt = null;

    /**
     * speedoql is the result of the filter parsing
     */
    private SimpleNode speedoql = null;

    private int nbNot = 0;

    private List orders;

    /**
     * field for each defined identifiers of the query.
     */
    private HashMap fields = new HashMap();

    private QueryBuilder qb = new QueryBuilder();
   
    public SpeedoQLVariableVisitor(SimpleNode speedoql,
            Manager jmim,
            Logger logger,
            Map hparam,
            Map hvar,
            List orders,
            String classname,
      boolean includeSubClasses
      ) throws SpeedoException {
        this.speedoql = speedoql;
        this.jmiManager= jmim;
        setLogger(logger);
        setParams(hparam);
        setVars(hvar);
        setOrders(orders);
        setCurrentClass(classname);
        this.includeSubClasses = includeSubClasses;
        startVisiting();
    }

    public Map getFields() {
        return fields;
    }
   
    public QueryBuilder getQueryBuilder() {
        return qb;
    }
   
    public QueryTree getQueryTree() {
        return qb.getQueryTree();
    }
   
    public void setOrders(List orders) {
        this.orders = orders;
    }

    /**
     * The visit of the tree starts here.
     * Please setup current class, params and vars hashtable before calling
     * this method.
     */
    public Map startVisiting() throws SpeedoException {
        debug = logger != null && logger.isLoggable(BasicLevel.DEBUG);
        nbNot = 0;

        //Add the initial class as the first IdValue. The key is 'this'
        if (curClass != null) {
            logger.log(BasicLevel.DEBUG, "create a new IdValue object " +
                    "with the current class (" + curClass + ")");
            IdValue iv = new IdValue(new String[] {curClass}, EXTENT);
            iv.alias = "this";
            ids.put(iv.alias, iv);
        }
        try {
            //visit the tree
            visit(speedoql);
        } catch (Exception e) {
            throw new SpeedoException("Error during the parsing of JDOQL:", e);
        }
        if (orders != null) {
            for(int i=0; i<orders.size(); i++) {
                String fieldName = (String) orders.get(i);
                int idx = fieldName.indexOf(' ');
                if (idx != -1) {
                    fieldName = fieldName.substring(0, idx).trim();
                }
                visitPath(null, fieldName);
            }
        }
        ArrayList toTreat = new ArrayList(ids.values());
        while(!toTreat.isEmpty()) {
            treatIdValue((IdValue) toTreat.get(0), toTreat);
        }
        return fields;
    }
   
    private void treatIdValue(IdValue iv, List toTreat) throws SpeedoException {
        if (iv.nameType != EXTENT) {
            IdValue dependency = (IdValue) ids.get(iv.name[0]);
            if (dependency == null) {
                throw new SpeedoException("Dependency unresolved: " + iv.name[0]);
            }
            if (toTreat.contains(dependency)) {
                treatIdValue(dependency, toTreat);
            }
        }
        toTreat.remove(iv);

        QueryBuilder theqb = qb;
        if (iv.nameType == MEMBEROF) {
            //a.b.cs.contains(x)  ==> a.b.PNAME IN cs.id
            String rest = mergePath(iv.name, 1, iv.name.length - 1);
            theqb = new QueryBuilder(qb);
            try {
                theqb.define("", qb.navigate(iv.name[0]));
            } catch (MedorException e) {
                throw new SpeedoException(e);
            }
        }

        try {
            String n = iv.alias + "." + Field.PNAMENAME;
            fields.put(n, theqb.project(iv.alias, define(theqb, iv.alias, iv.alias)));
            for (int i = 0; i < iv.getDeclaredPathLength(); i++) {
                String path = iv.getMergedPath(i);
                if (!testcontains.contains(path) && !isEmptys.contains(path)) {
                    fields.put(path, theqb.project(path, define(theqb, path, null)));
                }
          }
        } catch (Exception e) {
            throw new SpeedoException("Error during the parsing of JDOQL:", e);
        }
    }
   
    public QueryTreeField getField(String path) throws SpeedoException {
        String[] splitted = splitPath(path);
        if (params != null && params.containsKey(splitted[0])) {
            if (splitted.length > 1) {
                //not managed
            }
        } else if (vars != null && vars.containsKey(splitted[0])) {
        } else { // this
            if (!splitted[0].equals("this")) {
                path = "this." + path;
                String[] newsplitted = new String[splitted.length + 1];
                newsplitted[0] = "this";
                System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
                splitted = newsplitted;
            }
        }
        QueryTreeField qtf = (QueryTreeField) fields.get(path);
        if (qtf == null) {
            try {
                qtf = qb.project(define(qb, path, null));
            } catch (Exception e) {
                throw new SpeedoException(e);
            }
            fields.put(path, qtf);
        }
        return qtf;
    }
   
    /**
     * ********************* VISITOR METHODS ***********************************
     */

    public Object visit(ASTSpeedoPrimary node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTSpeedoQL node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTPrimary node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTRelationalExpression node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTAdditiveExpression node, Object data) {

        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTUnaryExpression node, Object data) {
        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);
            }
        }
        //logger.log(BasicLevel.DEBUG, "End of Visit UnaryExpression");
        return null;
    }

    public Object visit(ASTCastExpression node, Object data) {
        return null;
    }

    public Object visit(ASTArgumentList node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTLiteral node, Object data) {
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTType node, Object data) {
        //voir cast , donc on s'en fout
        visit((SimpleNode) node, data);
        return null;
    }

    public Object visit(ASTQualifiedName node, Object data) {
        Stack stack = (Stack) data;
        String name = (String) node.value;
        if (debug) {
            logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">");
        }
        visitPath(stack, name);
        if (debug) {
            logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">-end");
        }
        return null;
    }
   
    private void visitPath(Stack stack, String path) {
        String[] splitted = splitPath(path);
        if (params != null && params.containsKey(splitted[0])) {
            visitParameterUse(stack, splitted);
        } else if (vars != null && vars.containsKey(splitted[0])) {
            visitVariableUse(stack, path, splitted);
        } else { // this
            if (!splitted[0].equals("this")) {
                path = "this." + path;
                String[] newsplitted = new String[splitted.length + 1];
                newsplitted[0] = "this";
                System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
                splitted = newsplitted;
            }
            visitThisUse(stack, path, splitted);
        }
    }

    /**
     * Manages a path using a parameter
     * @param stack
     * @param splitted
     */
    private void visitParameterUse(Stack stack, String[] splitted) {
        if (stack.size() > 0 && stack.peek() instanceof String) {
            String setpath = (String) stack.pop();
            if (debug) {
                logger.log(BasicLevel.DEBUG, "The parameter '" + splitted[0]
                    + "' is used in a contains expression: "
                    + setpath + ".contains(" + splitted[0] + ")");
            }
        } else if (debug) {
            logger.log(BasicLevel.DEBUG, "Use of the parameter " + splitted[0]);
        }
    }
   
    /**
     * Manages a path using a variable
     * @param stack
     * @param path
     * @param splitted
     */
    private void visitVariableUse(Stack stack, String path, String[] splitted) {
        if (debug) {
            logger.log(BasicLevel.DEBUG, "Use of the variable " + splitted[0]
                + " : " + path);
        }
        //fetch or create an IdValue
        IdValue iv = (IdValue) ids.get(splitted[0]);
        if (iv == null) {
            if (debug) {
                logger.log(BasicLevel.DEBUG, "Create a new IdValue for the variable " + splitted[0] + " for the path " + path);
            }
            iv = new IdValue();
            // The definition of the variable is not yet knwon but by default
            // the variable is used a simple extent (JORM_NAME)
            iv.nameType = EXTENT;
            iv.alias = splitted[0];
            ids.put(iv.alias, iv);
        } else {
            if (iv.alias !=null && !iv.alias.equals(splitted[0])) {
                logger.log(BasicLevel.WARN,
                        "Redefine a different alias for a variable, old="
                        + iv.alias + ", new=" + splitted[0]);
            }
            iv.alias = splitted[0];
            if (debug) {
                logger.log(BasicLevel.DEBUG, "Use the IdValue of the variable " + splitted[0] + " by the path " + path);
            }
        }
        if (stack.size() > 0 && stack.peek() instanceof String) {
            // Define the IdValue from previous (contains)
            String definition = (String) stack.pop();
            if (debug) {
                logger.log(BasicLevel.DEBUG, "Define the variable " + splitted[0]
                    + " to " + definition);
            }
            if (iv.name != null) {
                throw new JDOUserException("Variable '"
                        + splitted[0] + "' defined several times : \n\t"
                        + iv.name + "\n\t" + definition);
            }
            iv.nameType = ((nbNot%2)==1 ? MEMBEROF : NAVIGATION);
            iv.name = splitPath(definition);
            testcontains.add(definition);
        }
        visitThisOrVarUseEnd(stack, path, splitted);
    }
   
    private void visitThisUse(Stack stack, String path, String[] splitted) {
        if (debug) {
            logger.log(BasicLevel.DEBUG, "Use of this " + splitted[0]
                + " : " + path);
        }
        IdValue iv = (IdValue) ids.get(splitted[0]);
        if (stack != null && stack.size() > 0 && stack.peek() instanceof String) {
            // Define the IdValue from previous (contains)
            String collectionpath = (String) stack.pop();
            if (debug) {
                logger.log(BasicLevel.DEBUG, "test collection membering " + path
                    + " IN " + collectionpath);
            }
            testcontains.add(collectionpath);
        }
        visitThisOrVarUseEnd(stack, path, splitted);
       
    }   
    /**
     * manage a path starting with 'this' or a variable
     * @param stack
     * @param path is the path using 'this' or a varible
     * @param splitted is the splitted path. The first String must be "this" or
     * a varible
     */
    private void visitThisOrVarUseEnd(Stack stack, String path, String[] splitted) {
        int operatorId = isMethodOperator(splitted[splitted.length - 1]);
        if (operatorId != -1) {
            //the last element is an operator
            String begin = buildStringwithout(splitted, splitted.length-1, ".");
            ((IdValue) ids.get(splitted[0])).addPath(begin);
            switch(operatorId) {
            case CONTAINS_OPERATOR:
                if (debug) {
                    logger.log(BasicLevel.DEBUG, "contains case, path: " + begin);
                }
                //stock in stack a mean to find the contains stuff...
                if (stack != null) {
                    stack.push(begin);
                }
                break;
            case IS_EMPTY_OPERATOR:
                if (debug) {
                    logger.log(BasicLevel.DEBUG, "isEmpty case, path: " + begin);
                }
                isEmptys.add(begin);
                break;
            }
            return;
        } else {
            if (debug) {
                logger.log(BasicLevel.DEBUG,
                        "Navigation case without operator, path:" + path);
            }
            ((IdValue) ids.get(splitted[0])).addPath(path);
        }
    }

}
TOP

Related Classes of org.objectweb.speedo.query.jdo.parser.SpeedoQLVariableVisitor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.