Package org.jpox.query.evaluator

Source Code of org.jpox.query.evaluator.JDOQLEvaluator

/**********************************************************************
Copyright (c) 2008 Erik Bengtson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.jpox.query.evaluator;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.jpox.ClassLoaderResolver;
import org.jpox.query.evaluator.memory.InMemoryExpressionEvaluator;
import org.jpox.query.expression.CreatorExpression;
import org.jpox.query.expression.Expression;
import org.jpox.query.expression.InvokeExpression;
import org.jpox.query.symbol.PropertySymbol;
import org.jpox.query.symbol.Symbol;
import org.jpox.query.symbol.SymbolTable;
import org.jpox.store.query.Parser;
import org.jpox.store.query.Query;
import org.jpox.util.Imports;
import org.jpox.util.JPOXLogger;

/**
* This class maps the result specified by setResult.
*/
public class JDOQLEvaluator
{
    private boolean aggregates;

    private boolean unique;
   
    private Expression[] grouping;
   
    private Expression[] ordering;

    private Expression having;

    Expression filter;
   
    Expression[] result;

    private Class resultClass;

    private long fromIncl;

    private long toExcl;

    SymbolTable symtbl;
    InMemoryExpressionEvaluator evaluator;
    List set;
    Query query;
    Imports imports;
    ClassLoaderResolver clr;

    /**
     * ResultMapper for handling the setResult instruction
     * @param set The Set containing objects already filtered by JDOQLFilterMap
     * @param result The string defined by setResult
     * @param resultClass The resultClass defined by setResultClass
     * @param unique Boolean defined by setUnique
     * @param grouping String defined by setGrouping
     */
    public JDOQLEvaluator(Query query, List set, Expression[] result, SymbolTable symtbl,
            Expression[] grouping, Expression[] ordering, Expression having, Expression filter,
            ClassLoaderResolver clr)
    {
        this.query = query;
        evaluator = new InMemoryExpressionEvaluator(symtbl, imports, clr);
        this.imports = query.getParsedImports();
        this.clr = clr;
        this.filter = filter;
        this.having = having;
        this.ordering = ordering;
        this.grouping = grouping;
        this.unique = query.isUnique();
        this.result = result;
        this.resultClass = query.getResultClass();
        this.symtbl = symtbl;
        this.set = set;
        this.fromIncl = query.getRangeFromIncl();
        this.toExcl = query.getRangeToExcl();

        // try to determinate fromInclNo and to ExclNo by the range string
        if (query.getRange() != null)
        {
            Parser p = new Parser(query.getRange(), new Imports());

            BigInteger from = p.parseIntegerLiteral();
            if (from != null)
            {
                this.fromIncl = from.longValue();
            }
            p.skipWS();
            if (p.parseChar(','))
            {
                p.skipWS();
                BigInteger to = p.parseIntegerLiteral();
                if (to != null)
                {
                    this.toExcl = to.longValue();
                }
            }
        }
    }

    public Collection execute()
    {
        List resultSet = null;

        // if the set is empty we return null
        if (set.size() == 0)
        {
            return set;
        }
        else
        {
            resultSet = new ArrayList(set);
        }

        resultSet = handleFilter(resultSet);
       
        if (JPOXLogger.DATASTORE.isDebugEnabled())
        {
            String msg = "Mapping the range Specification: " + fromIncl + " " + toExcl;
            JPOXLogger.DATASTORE.debug(msg);
        }

        resultSet = ordering(resultSet);
        //TODO solve order?
        resultSet = handleRange(resultSet);

        if (JPOXLogger.DATASTORE.isDebugEnabled())
        {
            String msg = "Mapping the setResult Specification: " + result;
            JPOXLogger.DATASTORE.debug(msg);
        }

        if (result != null)
        {

            List aggregateList = new ArrayList();
            List s = set;
            if (grouping != null)
            {
                s = sortByGrouping(set);
            }

            aggregateList = s;
            if (grouping != null)
            {
                aggregateList = handleAggregates(s);
            }

            resultSet = handleResult(aggregateList);
        }

        if (resultClass != null && !(result[0] instanceof CreatorExpression))
        {
            return this.mapResultClass(resultSet);
        }
        return resultSet;
    }

    private List handleFilter(List set)
    {
        if (filter == null)
        {
            return set;
        }

        List result = new ArrayList();
        Iterator it = set.iterator();
        while (it.hasNext())
        {
            Object obj = it.next();
            // TODO Remove HARDCODED "this". Should be alias of some name
            symtbl.getSymbol("this").setValue(obj);
            if (filter.evaluate(new InMemoryExpressionEvaluator(symtbl, imports, clr)) == Boolean.TRUE)
            {
                result.add(obj);
            }
        }
        return result;
    }

    private List handleRange(List set)
    {
        if (toExcl-fromIncl <=0)
        {
            return Collections.EMPTY_LIST;
        }
        else
        {
            List resultList = new ArrayList();
            Iterator it = set.iterator();
            // skipping the unnecessary objects
            for (long l = 0; l < fromIncl && it.hasNext(); l++)
            {
                it.next();
            }
            long l = 0;
            while (l < (toExcl - fromIncl) && it.hasNext())
            {
                resultList.add(it.next());
                l++;
            }
            return resultList;
        }
    }

    private List sortByGrouping(List set)
    {
        Object[] o = set.toArray();
        Arrays.sort(o, new Comparator()
        {
            public int compare(Object arg0, Object arg1)
            {
                for( int i=0; i<grouping.length; i++)
                {
                    symtbl.getSymbol("this").setValue(arg0);
                    Object a = grouping[i].evaluate(evaluator);
                    symtbl.getSymbol("this").setValue(arg1);
                    Object b = grouping[i].evaluate(evaluator);
                    int result = ((Comparable)a).compareTo(b);
                    if( result != 0)
                    {
                        return result;
                    }
                }
                return 0;
            }
        });
        return Arrays.asList(o);
    }   

    private List ordering(List set)
    {
        if (ordering == null)
        {
            return set;
        }
        Symbol symbol = new PropertySymbol("set");
        if (symtbl.hasSymbol("set"))
        {
            symbol = symtbl.getSymbol("set");
        }
        else
        {
            symtbl.addSymbol(symbol);
        }
        symbol.setValue(set);
        Object[] o = set.toArray();
        Arrays.sort(o, new Comparator()
        {
       
            public int compare(Object arg0, Object arg1)
            {
                for( int i=0; i<ordering.length; i++)
                {
                    symtbl.getSymbol("this").setValue(arg0);
                    Object a = ordering[i].evaluate(new InMemoryExpressionEvaluator(symtbl, imports, clr));
                    symtbl.getSymbol("this").setValue(arg1);
                    Object b = ordering[i].evaluate(new InMemoryExpressionEvaluator(symtbl, imports, clr));
                    int result = ((Comparable)a).compareTo(b);
                    if( result != 0)
                    {
                        return result;
                    }
                }
                return 0;
            }
       
        });
        return Arrays.asList(o);
    }   

    /**
     * Checks if set is fulfilling having clause
     * @param set
     * @return true if fulfilling having clause
     */
    private boolean satisfiesHavingClause(List set)
    {
        Symbol symbol = new PropertySymbol("set");
        if (symtbl.hasSymbol("set"))
        {
            symbol = symtbl.getSymbol("set");
        }
        else
        {
            symtbl.addSymbol(symbol);
        }
        symbol.setValue(set);
        if (having.evaluate(evaluator) == Boolean.TRUE)
        {
            return true;
        }
        return false;
    }

    /**
     * Checks if there are aggregates and handles it
     * @param resultSet The resultSet containing al elements
     * @return A list with aggregated elements
     */
    private List handleAggregates(List resultSet)
    {
        Comparator c = new Comparator()
        {
            public int compare(Object arg0, Object arg1)
            {
                for( int i=0; i<grouping.length; i++)
                {
                    symtbl.getSymbol("this").setValue(arg0);
                    Object a = grouping[i].evaluate(evaluator);
                    symtbl.getSymbol("this").setValue(arg1);
                    Object b = grouping[i].evaluate(evaluator);
                    int result = ((Comparable)a).compareTo(b);
                    if( result != 0)
                    {
                        return result;
                    }
                }
                return 0;
            }
       
        };
        List groups = new ArrayList();
        List group = new ArrayList();
        groups.add(group);
        for (int i=0; i<resultSet.size(); i++)
        {
            if (i > 0)
            {
                if (c.compare(resultSet.get(i-1),resultSet.get(i)) != 0)
                {
                    group = new ArrayList();
                    groups.add(group);
                }
            }
            group.add(resultSet.get(i));
        }
        List result = new ArrayList();
        if (having != null)
        {
            for(int i=0; i<groups.size(); i++)
            {
                if (satisfiesHavingClause((List) groups.get(i)))
                {
                    result.addAll((Collection) groups.get(i));
                }
            }
        }
        else
        {
            for (int i = 0; i < groups.size(); i++)
            {
                result.addAll((Collection) groups.get(i));
            }
        }
        return result;
    }

    /**
     * Checks if there are aggregates and handles it
     * @param resultSet The resultSet containing al elements
     * @return A list with aggregated elements
     */
    private List handleResult(List resultSet)
    {
        Comparator c = new Comparator()
        {
            public int compare(Object arg0, Object arg1)
            {
                if (grouping != null)
                {
                    for (int i = 0; i < grouping.length; i++)
                    {
                        // TODO Remove HARDCODED "this". Should be alias of some name
                        symtbl.getSymbol("this").setValue(arg0);
                        Object a = grouping[i].evaluate(evaluator);
                        // TODO Remove HARDCODED "this". Should be alias of some name
                        symtbl.getSymbol("this").setValue(arg1);
                        Object b = grouping[i].evaluate(evaluator);
                        int result = ((Comparable) a).compareTo(b);
                        if (result != 0)
                        {
                            return result;
                        }
                    }
                }
                return 0;
            }
        };

        List result = new ArrayList();
        if (grouping != null)
        {
            List groups = new ArrayList();
            List group = new ArrayList();
            if (resultSet.size() > 0)
            {
                groups.add(group);
            }
            for (int i = 0; i < resultSet.size(); i++)
            {
                if (i > 0)
                {
                    if (c.compare(resultSet.get(i - 1), resultSet.get(i)) != 0)
                    {
                        group = new ArrayList();
                        groups.add(group);
                    }
                }
                group.add(resultSet.get(i));
            }
            if (result != null)
            {
                for (int i = 0; i < groups.size(); i++)
                {
                    result.add(result((List) groups.get(i)));
                }
            }
        }
        else
        {
            if (this.result.length > 0 && this.result[0] instanceof CreatorExpression)
            {
                Expression[] resExpr = (Expression[]) ((CreatorExpression) this.result[0]).getParameters().toArray(
                    new Expression[((CreatorExpression) this.result[0]).getParameters().size()]);
                for (int i = 0; i < resExpr.length; i++)
                {
                    if (resExpr[i] instanceof InvokeExpression)
                    {
                        String method = ((InvokeExpression) resExpr[i]).getOperation();
                        if (method.equals("count") || method.equals("sum") || method.equals("avg") ||
                            method.equals("min") || method.equals("max"))
                        {
                            aggregates = true;
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < this.result.length; i++)
                {
                    if (this.result[i] instanceof InvokeExpression)
                    {
                        String method = ((InvokeExpression) this.result[i]).getOperation();
                        if (method.equals("count") || method.equals("sum") || method.equals("avg") ||
                            method.equals("min") || method.equals("max"))
                        {
                            aggregates = true;
                        }
                    }
                }
            }
            if (aggregates)
            {
                result.add(result(resultSet));
            }
            else
            {
                for (int i = 0; i < resultSet.size(); i++)
                {
                    result.add(result(resultSet.get(i)));
                }
            }
        }
        if (result.size() > 0 && ((Object[]) result.get(0)).length == 1)
        {
            List r = result;
            result = new ArrayList();
            for (int i = 0; i < r.size(); i++)
            {
                result.add(((Object[]) r.get(i))[0]);
            }
        }
        return result;
    }

    private Object[] result(Object obj)
    {
        Symbol symbol = symtbl.getSymbol("this");
        symbol.setValue(obj);
        Object[] r = new Object[result.length];
        for (int i=0; i<result.length; i++)
        {
            r[i] = result[i].evaluate(evaluator);
        }

        return r;
    }

    private Object[] result(List set)
    {
        Symbol symbol = new PropertySymbol("set");
        if( symtbl.hasSymbol("set"))
        {
            symbol = symtbl.getSymbol("set");
        }
        else
        {
            symtbl.addSymbol(symbol);
        }
        symbol.setValue(set);
        Object[] r = new Object[result.length];
        for( int i=0; i<result.length; i++)
        {
            r[i] = result[i].evaluate(evaluator);
        }
        return r;
    }

    /**
     * Checks if single row should be returned
     * @return True if single row should be returned.
     */
    public boolean shouldReturnSingleRow()
    {
        if (query.isUnique())
        {
            return true;
        }
        if (query.getGrouping() != null)
        {
            return false;
        }
        // The JDO spec says nothing about this here. It only says a single row if unique specified,
        // or grouping, or aggregates
        /*if ((toExcl - fromIncl) == 1)
        {
            return true;
        }*/
        if (aggregates)
        {
            // TODO This is incomplete. It should check if ALL results are aggregates and in that case use single row
            return true;
        }
        return false;
    }

    /**
     * Constructs ResultClassMapper and calls its map function
     * @param resultSet The resultSet containing the instances handeld by setResult
     * @return The resultSet containing instances of the Class defined by setResultClass
     */
    private Collection mapResultClass(Collection resultSet)
    {
        return new JDOQLResultClassMapper(resultClass).map(resultSet, result);
    }
}
TOP

Related Classes of org.jpox.query.evaluator.JDOQLEvaluator

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.