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

Java Open Source » Database ORM » Speedo_1.4.5 
Speedo_1.4.5 » org » objectweb » speedo » query » jdo » JDOCompiledSelectQuery.java
/**
 * Speedo: an implementation of JDO compliant personality on top of JORM generic
 * I/O sub-system.
 * Copyright (C) 2001-2006 France Telecom
 *
 * 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;

import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.metainfo.api.Manager;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.medor.api.EvaluationException;
import org.objectweb.medor.api.MedorException;
import org.objectweb.medor.eval.lib.SelectEvaluator;
import org.objectweb.medor.expression.api.ExpressionException;
import org.objectweb.medor.expression.api.Operand;
import org.objectweb.medor.expression.api.ParameterOperand;
import org.objectweb.medor.query.api.OrderField;
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.BasicOrderField;
import org.objectweb.medor.query.lib.QueryTreePrinter;
import org.objectweb.medor.query.lib.SelectProject;
import org.objectweb.medor.tuple.api.TupleCollection;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.mim.api.HomeItf;
import org.objectweb.speedo.pm.jdo.api.JDOPOManagerItf;
import org.objectweb.speedo.query.api.QueryDefinition;
import org.objectweb.speedo.query.jdo.parser.ASTSpeedoQL;
import org.objectweb.speedo.query.jdo.parser.ParseException;
import org.objectweb.speedo.query.jdo.parser.SelectGroupByVisitor;
import org.objectweb.speedo.query.jdo.parser.SimpleNode;
import org.objectweb.speedo.query.jdo.parser.SpeedoQL;
import org.objectweb.speedo.query.jdo.parser.SpeedoQLQueryFilterVisitor;
import org.objectweb.speedo.query.jdo.parser.SpeedoQLVariableVisitor;
import org.objectweb.speedo.usercache.lib.UserCacheKey;
import org.objectweb.speedo.workingset.api.TransactionItf;
import org.objectweb.util.monolog.api.BasicLevel;

import java.io.CharArrayReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.jdo.JDOException;

/**
 * JDOCompiledQuery object represents a jdo query. This object is created
 * when a new query is created, and can be used several times. A list of
 * JDOCompiledQuery is managed with a JDOQueryManager component.
 * When a user creates a new JDO Query object (SpeedoQuery), a
 * JDOCompiledQuery object is associated to the JDOQuery object which is
 * used to delegate some methods.
 * 
 * @author S.Chassande-Barrioz
 */
public class JDOCompiledSelectQuery extends JDOAbstractCompiledQuery {

    private JDOQueryEvalContext[] qecs = null;
    private Class[] selectedFieldTypes = null;

    public JDOQueryEvalContext[] getQueryEvalContext() {
        return qecs;
    }


    /**
     * compile the current SpeedoCompiledQuery.
     * The query is prepared to be executed.
     * The PersistenceManager is set (even if there was a previous definition
     * of a PersistenceManager.
     */
    public synchronized void compile() throws SpeedoException, MedorException, ExpressionException {
        if (status == UNDEFINED)
            throw new SpeedoException("Impossible to compile an undefined query");
        if (status == COMPILED)
            return;
    long timeToCompile = System.currentTimeMillis();
        boolean debug = logger.isLoggable(BasicLevel.DEBUG);
        // create a speedoQL object with a filter string
      String filter = qd.filter;
      filter = '(' + filter + ')';
        // create representations of the parameters list and the variable
        // list
        toHashtableParams(qd.parameters, ";,");
        toHashtableVars(qd.variables, ";,");
        Manager miManager = mapper.getMetaInfoManager();
        if (miManager == null)
            throw new SpeedoException(
                    "A non null Meta information manager is needed");
        try {
          jf.getPClassMapping(
              qd.candidateClass.getName(),
          classLoader);
        } catch (Exception e) {
      throw new SpeedoException(e);
    }
        SimpleNode node = null;
        try {
            node = new SpeedoQL(new CharArrayReader(filter.toCharArray())).SpeedoQL();
        } catch (ParseException e) {
            throw new SpeedoException(
                    "Impossible to parse the filter and to create AST", e);
        }
        SpeedoQLVariableVisitor sqvv = new SpeedoQLVariableVisitor(
                node, miManager, varParserlogger, hparams, hvars, qd.order,
                qd.candidateClass.getName(), qd.includeSubClasses); 
        // start the variable visitor to catch all variables and build a
        // first tree of them without collection navigation
        Map fields = sqvv.getFields();
        QueryBuilder qb = sqvv.getQueryBuilder();
        QueryTree qt = sqvv.getQueryTree();

        SelectProject sp = new SelectProject("");
        if (!filter.equals("(true)") && !filter.equals("true")) {
            //Ther is a filter and potentialy collection navigation
            if (debug) {
                logger.log(BasicLevel.DEBUG, "filter = " + qd.filter);
            }
            // start the query filter visitor, to build and expression tree of
            // the filter expression
            SpeedoQLQueryFilterVisitor sqfv = new SpeedoQLQueryFilterVisitor(
                    fields, sp, (ASTSpeedoQL) node, 
                    filterParserLogger, hparams, hvars, 
                    qd.candidateClass,
                    qb, jf);
            sp.setQueryFilter(sqfv.getQueryFilter());
        }
        assignMapper(sp);
        assignMapper(qt);

    JDOQueryEvalContext qec = new JDOQueryEvalContext(sp, this);
    
    SelectGroupByVisitor sgv = new SelectGroupByVisitor(
            sp, qt, mapper, sqvv, qec, classLoader);
    
    sgv.visit(qd);
    selectedFieldTypes = sgv.getSelectFieldTypes();
        assignMapper(qec.query);
    
    //Specify the ordering
        if (qd.order != null && qd.order.size() > 0) {
      OrderField[] ofs = new OrderField[qd.order.size()];
      for(int i=0; i<ofs.length; i++) {
        String o = (String) qd.order.get(i);
        int idx = o.indexOf(' ');
        boolean desc = false;
        if (idx != -1) {
          desc = o.substring(idx + 1).trim().equals("descending");
          o = o.substring(0, idx);
        }
        o = "this." + o;
        ofs[i] = new BasicOrderField((QueryTreeField)
          qt.getTupleStructure().getField(o), desc);
      }
      sp.setOrderBy(ofs);
    }

    logger.log(BasicLevel.INFO, "QueryTree built");
        if (debug) {
            QueryTreePrinter.printQueryTree(qec.query, logger);
        }
    //check for the use of the userCache
        if (qd.result == null && qd.variables == null) {
            //no variable used and the result is the candidate class
            Map field2value = new HashMap();
            if (getFieldComparaison(sp.getQueryFilter(), field2value)) {
                HomeItf sh = null;
                try {
                    sh = (HomeItf) jf.getPClassMapping(
                            qd.candidateClass.getName(),
                            classLoader);
                } catch (PException e) {
                    //never happen
                }
                userCache = sh.getUserCache(field2value.keySet());
                if (userCache != null) {
                    userCacheIndexes = new Operand[field2value.size()];
                    String[] ifs = userCache.getIndexFieldNames();
                    for (int i = 0; i < ifs.length; i++) {
                        userCacheIndexes[i] = (Operand) field2value.get(ifs[i]);
                    }
                }
            }
            
        }
        
    // Optimize the queryTree
    qec.query = optimize(qec.query, debug);
    
    // Creates an evaluator associated to the QueryTree
    qec.evaluator = new SelectEvaluator(qec.query, 0);
    
    qecs = new JDOQueryEvalContext[] {qec};
    timeToCompile = System.currentTimeMillis() - timeToCompile;
        status = COMPILED;
        logger.log(BasicLevel.INFO, "Query compiled in " + timeToCompile + "ms");
    }



    /**
     * executes a the current query, and returns a Collection of object.
     * @param userqd is the user query definition. It contains the range values
     * and some other values that can change from the original compiled query.
     * @return  a new Collection of objects.
     * @throws org.objectweb.medor.api.EvaluationException
     * @throws org.objectweb.medor.api.MedorException
     */
  protected Object executeQT(JDOPOManagerItf pm, ParameterOperand[] pos, QueryDefinition userqd)
        throws EvaluationException, MedorException, SpeedoException {
        flushCache(pm);
    if (userCache != null) { //the query matches to an unique index
        Object key = null;
        //building the key
        if (userCacheIndexes.length == 1) {
            //Index is single
            key = getValueFromOperand(userCacheIndexes[0], pos);
        } else {
            //key is composite
            key = new UserCacheKey(userCacheIndexes.length);
            for (int i = 0; i < userCacheIndexes.length; i++) {
                ((UserCacheKey) key).setPart(i, 
                        getValueFromOperand(userCacheIndexes[0], pos));
                }
        }
        // search in the user cache
        key = userCache.lookup(key);
        if (key != null) {
            try {
                    if (key instanceof PName) { //the cache contains PName
                        key = pm.getObjectById(key, false);
                    }
                    if (qd.unique) {
                        return key;
                    } else {
                        return Collections.singletonList(key);
                    }
                } catch (JDOException e) {
                    logger.log(BasicLevel.WARN, 
                            "User cache is not up to date:", e);
                }
        }
    }
    
        Object connection = ((TransactionItf) pm.currentTransaction())
        .getConnectionHolder();
        //fetch the result as TupleCollection 
    TupleCollection queryResult = null;
    if (qecs.length == 1) {
      //optimization: avoid to use an intermediate class
      queryResult = qecs[0].eval(pm, pos, connection, userqd);
      if (queryResult == null || queryResult.isEmpty()) {
        logger.log(BasicLevel.INFO,
            "Be careful, the result is empty");
        if (queryResult != null) {
            queryResult.close();
        }
        JDOQueryResultCommon.closeConnection(connection);
        if (qd.unique) {
            return null;
        } else {
            return Collections.EMPTY_SET;
        }
      }
    } else {
      //Use a multiplex of query
      queryResult = new JDOQueriesUnion(pos, pm, connection, qecs, userqd);
    }
    if (qd.unique) {
            //Only one object is expected, then return it
        return new JDOQueryResultUnique(
                queryResult, 
                pm, 
                new Object[]{connection},
                qd.resultClass,
                selectedFieldTypes,
                qecs.length == 1,
                    userqd.fetchIdentifierOnly(),
                logger).getResult();
    } else {
            //the expected result size is greater than one, then 
            // a result container is use (List) 
        return new JDOQueryResultList(
                queryResult, 
                pm, 
                new Object[]{connection},
                qd.resultClass,
                selectedFieldTypes,
                qecs.length == 1,
                    userqd.fetchIdentifierOnly(),
                logger);
    }
    }

  private Object getValueFromOperand(Operand op, ParameterOperand[] pos) {
      if (op instanceof ParameterOperand) {
          String param = ((ParameterOperand) op).getName();
          for (int i = 0; i < pos.length; i++) {
                if (pos[i].getName().equals(param)) {
                    return pos[i].getObject();
                }
            }
        return null;
      } else {
          return op.getObject();
      }
  }
  
}
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.