You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 20:09:00 UTC

svn commit: r171353 [3/13] - in /incubator/jdo/trunk/query20: ./ src/ src/conf/ src/java/ src/java/org/ src/java/org/apache/ src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/jdoql/ src/java/org/apache/jdo/impl/jdoql/jdoqlc/ src/java/org/apache/jdo/impl/jdoql/scope/ src/java/org/apache/jdo/impl/jdoql/tree/ src/java/org/apache/jdo/jdoql/ src/java/org/apache/jdo/jdoql/tree/

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryImpl.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryImpl.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryImpl.java Sun May 22 11:08:57 2005
@@ -0,0 +1,732 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * QueryImpl.java
+ *
+ * Created on August 31, 2001
+ */
+
+package org.apache.jdo.impl.jdoql;
+
+import java.io.IOException;
+import java.util.*;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.Query;
+import javax.jdo.Extent;
+import javax.jdo.Transaction;
+
+import org.apache.jdo.impl.jdoql.jdoqlc.JDOQLAST;
+import org.apache.jdo.impl.jdoql.jdoqlc.JDOQLC;
+import org.apache.jdo.impl.jdoql.scope.ParameterTable;
+import org.apache.jdo.impl.jdoql.scope.VariableTable;
+import org.apache.jdo.impl.jdoql.tree.Tree;
+import org.apache.jdo.jdoql.JDOQueryException;
+import org.apache.jdo.query.QueryResult;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.store.StoreManager;
+import org.apache.jdo.util.I18NHelper;
+
+
+/** 
+ * This class implements the JDO query interface 
+ * (see {@link javax.jdo.Query}).
+ *
+ * @author  Michael Bouschen
+ */
+public class QueryImpl
+    implements Query
+{
+    /** The pm for this query instance. */
+    private transient PersistenceManagerInternal pm;
+
+    /** The candidate class as specified by setClass. */
+    private transient Class candidateClass;
+
+    /** The name of the candidate class (Needed for serialization support). */
+    private String candidateClassName;
+
+    /** The candidates as specified by setCandidates. */
+    private transient Object candidates;
+    
+    /** The import declaration string as specified by declareImports. */
+    private String importDeclarations;
+    
+    /** The parameter declaration string as specified by declareParameters. */
+    private String parameterDeclarations;
+    
+    /** The variable declaration string as specified by declareVariables. */
+    private String variableDeclarations;
+    
+    /** The ordering specification string as specified by setOrdering. */
+    private String orderingSpecification;
+
+    /** The filter expression string as specified by setFilter. */
+    private String filterExpression;
+    
+    /** 
+     * The ignoreCache flag as specified by setIgnoreCache. The constructor
+     * defaults it to the PM setting.
+     */
+    private boolean ignoreCache;
+
+    /** The internal query representation as compilation result. */
+    private transient Tree compiledTree = null;
+    
+    /** 
+     * The internal query representation set by the constructor taking a 
+     * compiled query.
+     */
+    private Tree queryTree;
+
+    /** Represents parameter values. */
+    private ParameterTable paramtab;
+
+    /** Represents variable values. */
+    private VariableTable vartab;
+
+    /** Set of open query result instances. */
+    private transient Set openQueryResults = new HashSet();
+    
+    /** I18N support */
+    private final static I18NHelper msg =  
+        I18NHelper.getInstance(QueryImpl.class);
+
+    /**
+     * Create an empty query instance with no elements.
+     */
+    public QueryImpl(PersistenceManagerInternal pm)
+    {
+        // check valid PersistenceManager
+        if (pm == null)
+            throw new JDOQueryException(msg.msg("EXC_UnboundQuery")); //NOI18N
+
+        this.pm = pm;
+        this.ignoreCache = pm.getIgnoreCache();
+        this.paramtab = new ParameterTable();
+        this.vartab = new VariableTable();
+    }
+    
+    /** 
+     * Create a new Query using elements from another Query.  The other Query
+     * must have been created by the same JDO implementation.  It might be active
+     * in a different PersistenceManager or might have been serialized and
+     * restored.
+     * <P>All of the settings of the other Query are copied to this Query,
+     * except for the candidate Collection or Extent.
+     * @param compiled another Query from the same JDO implementation
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Object compiled)
+    {
+        this(pm);
+        if (compiled == null) {
+            throw new JDOQueryException(
+                msg.msg("EXC_NullQueryInstance")); //NOI18N
+        }
+        
+        if (compiled instanceof QueryImpl) {
+            QueryImpl other = (QueryImpl)compiled;
+            if (other.candidateClass != null) {
+                this.candidateClass = other.candidateClass;
+            }
+            else if (other.candidateClassName != null) {
+                // Support for deserialized query instances: 
+                // after deserialization other.candidateClass is not set,
+                // but other.candidateClassName is set => 
+                // use PM algorithm to calculate the candidateClass instance
+                try {
+                    this.candidateClass = 
+                        pm.loadClass(other.candidateClassName, null);
+                }
+                catch (ClassNotFoundException ex) {
+                    throw new JDOQueryException(
+                        msg.msg("EXC_UnknownCandidateClass", //NOI18N
+                                other.candidateClassName), ex);
+                }
+            }
+            this.importDeclarations = other.importDeclarations;
+            this.parameterDeclarations = other.parameterDeclarations;
+            this.variableDeclarations = other.variableDeclarations;
+            this.orderingSpecification = other.orderingSpecification;
+            this.filterExpression = other.filterExpression;
+            this.ignoreCache = other.ignoreCache;
+            // Set compiled tree to null in order to ensure that this Query 
+            // instance is compiled prior to execution.
+            // A possible optimization might want to reuse compilation results 
+            // from the other query, but this requires serializing the typeInfo
+            // from the JDOQLAST.
+            this.compiledTree = null;
+            this.queryTree = other.queryTree;
+            this.paramtab = other.paramtab;
+            this.vartab = other.vartab;
+            checkQueryTreeCandidateClass();
+        }
+        else if (compiled instanceof Tree) {
+            this.queryTree = (Tree)compiled;
+            // TBD: check compiledTree?
+            this.compiledTree = null;
+            checkQueryTreeCandidateClass();
+        }
+        else {
+            throw new JDOQueryException(
+                msg.msg("EXC_InvalidCompiledQuery", //NOI18N
+                        compiled.getClass().getName()));
+        }
+    }
+
+    /** 
+     * Create a new Query specifying the Class of the candidate instances.
+     * @param cls the Class of the candidate instances
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Class cls)
+    {
+        this(pm);
+        setClass(cls);
+    }
+    
+    /** 
+     * Create a new Query with the candidate Extent; the class 
+     * is taken from the Extent.
+     * @param cln the Extent of candidate instances
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Extent cln)
+    {
+        this(pm);
+        setClass(cln.getCandidateClass());
+        setCandidates(cln);
+    }
+    
+    /**
+     * Create a query instance with the candidate class and 
+     * candidate collection specified.
+     * @param cls the Class of the candidate instances.
+     * @param cln the Collection of candidate instances.
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Class cls, Collection cln)
+    {
+        this(pm);
+        setClass(cls);
+        setCandidates(cln);
+    }
+    
+    /** 
+     * Create a new Query with the Class of the candidate instances and Filter.
+     * @param cls the Class of results
+     * @param filter the filter for candidate instances
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Class cls, String filter)
+    {
+        this(pm);
+        setClass(cls);
+        setFilter(filter);
+    }
+        
+    /** 
+     * Create a new Query with the Class of the candidate instances, 
+     * candidate Collection, and filter.
+     * @param cls the Class of candidate instances
+     * @param cln the Collection of candidate instances
+     * @param filter the filter for candidate instances
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Class cls, Collection cln, 
+                     String filter)
+    {
+        this(pm);
+        setClass(cls);
+        setCandidates(cln);
+        setFilter(filter);
+    }
+    
+    /** 
+     * Create a new Query with the
+     * candidate Extent and filter; the class
+     * is taken from the Extent.
+     * @param cln the Extent of candidate instances
+     * @param filter the filter for candidate instances
+     */
+    public QueryImpl(PersistenceManagerInternal pm, Extent cln, String filter)
+    {
+        this(pm);
+        setClass(cln.getCandidateClass());
+        setCandidates(cln);
+        setFilter(filter);
+    }
+
+    /** Set the class of the candidate instances of the query.
+     * <P>The class specifies the class
+     * of the candidates of the query.  Elements of the candidate collection
+     * that are of the specified class are filtered before being
+     * put into the result Collection.
+     *
+     * @param cls the Class of the candidate instances.
+     */
+    public void setClass(Class cls)
+    {
+        synchronized (this.paramtab) {
+            this.candidateClass = cls;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Set the candidate Extent to query.
+     * @param pcs the Candidate Extent.
+     */
+    public void setCandidates(Extent pcs)
+    {
+        synchronized (this.paramtab) {
+            this.candidates = pcs;
+        }
+    }
+    
+    /** 
+     * Set the candidate Collection to query.
+     * @param pcs the Candidate collection.
+     */
+    public void setCandidates(Collection pcs)
+    {
+        synchronized (this.paramtab) {
+            this.candidates = pcs;
+        }
+    }
+    
+    /** 
+     * Set the filter for the query.
+     * @param filter the query filter.
+     */
+    public void setFilter(String filter)
+    {
+        synchronized (this.paramtab) {
+            this.filterExpression = filter;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Set the import statements to be used to identify the fully qualified name 
+     * of variables or parameters.  Parameters and unbound variables might 
+     * come from a different class from the candidate class, and the names 
+     * need to be declared in an import statement to eliminate ambiguity. 
+     * Import statements are specified as a String with semicolon-separated 
+     * statements. 
+     * <P>The String parameter to this method follows the syntax of the  
+     * import statement of the Java language.
+     * @param imports import statements separated by semicolons.
+     */
+    public void declareImports(String imports)
+    {
+        synchronized (this.paramtab) {
+            this.importDeclarations = imports;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Declare the list of parameters query execution.
+     *
+     * The parameter declaration is a String containing one or more query 
+     * parameter declarations separated with commas. Each parameter named 
+     * in the parameter declaration must be bound to a value when 
+     * the query is executed.
+     * <P>The String parameter to this method follows the syntax for formal 
+     * parameters in the Java language. 
+     * @param parameters the list of parameters separated by commas.
+     */
+    public void declareParameters(String parameters)
+    {
+        synchronized (this.paramtab) {
+            this.parameterDeclarations = parameters;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Declare the unbound variables to be used in the query. Variables 
+     * might be used in the filter, and these variables must be declared 
+     * with their type. The unbound variable declaration is a String 
+     * containing one or more unbound variable declarations separated 
+     * with semicolons. It follows the syntax for local variables in 
+     * the Java language.
+     * @param variables the variables separated by semicolons.
+     */
+    public void declareVariables(String variables)
+    {
+        synchronized (this.paramtab) {
+            this.variableDeclarations = variables;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Set the ordering specification for the result Collection.  The
+     * ordering specification is a String containing one or more ordering
+     * declarations separated by commas.
+     *
+     * <P>Each ordering declaration is the name of the field on which
+     * to order the results followed by one of the following words:
+     * "ascending" or "descending".
+     *
+     *<P>The field must be declared in the candidate class or must be
+     * a navigation expression starting with a field in the candidate class.
+     *
+     *<P>Valid field types are primitive types except boolean; wrapper types 
+     * except Boolean; BigDecimal; BigInteger; String; and Date.
+     * @param ordering the ordering specification.
+     */
+    public void setOrdering(String ordering)
+    {
+        synchronized (this.paramtab) {
+            this.orderingSpecification = ordering;
+            this.compiledTree = null;
+        }
+    }
+    
+    /** 
+     * Set the ignoreCache option.  The default value for this option was
+     * set by the PersistenceManagerFactory or the PersistenceManager used 
+     * to create this Query.
+     *
+     * The ignoreCache option setting specifies whether the query should execute
+     * entirely in the back end, instead of in the cache.  If this flag is set
+     * to true, an implementation might be able to optimize the query
+     * execution by ignoring changed values in the cache.  For optimistic
+     * transactions, this can dramatically improve query response times.
+     * @param ignoreCache the setting of the ignoreCache option.
+     */
+    public void setIgnoreCache(boolean ignoreCache)
+    {
+        synchronized (this.paramtab) {
+            this.ignoreCache = ignoreCache;
+        }
+    }
+    
+    /** 
+     * Get the ignoreCache option setting.
+     * @return the ignoreCache option setting.
+     * @see #setIgnoreCache
+     */
+    public boolean getIgnoreCache()
+    {
+        return ignoreCache;
+    }
+    
+    /** 
+     * Verify the elements of the query and provide a hint to the query to
+     * prepare and optimize an execution plan.
+     */
+    public void compile()
+    {
+        // check valid PersistenceManager
+        if (pm == null)
+            throw new JDOQueryException(msg.msg("EXC_UnboundQuery")); //NOI18N
+        
+        synchronized (this.paramtab) {
+            if (this.compiledTree == null) {
+                JDOQLC jdoqlc = new JDOQLC(pm);
+                if (queryTree != null) {
+                    jdoqlc.setQueryTree(queryTree);
+                }
+                else {
+                    // define the query parts including syntax checks
+                    jdoqlc.setClass(candidateClass);
+                    jdoqlc.declareImports(importDeclarations);
+                    jdoqlc.declareParameters(parameterDeclarations);
+                    jdoqlc.declareVariables(variableDeclarations);
+                    jdoqlc.setFilter(filterExpression);
+                    jdoqlc.setOrdering(orderingSpecification);
+                }
+
+                // call semantic analysis
+                JDOQLAST ast = jdoqlc.semanticCheck(paramtab, vartab);
+                // call optimizer
+                compiledTree = (Tree)jdoqlc.optimize(ast);
+            }
+        }
+    }
+    
+    /** 
+     * Execute the query and return the filtered Collection.
+     * @return the filtered Collection.
+     * @see #executeWithArray(Object[] parameters)
+     */
+    public Object execute()
+    {
+        synchronized (this.paramtab) {
+            compile();
+            pm.assertIsOpen();
+            checkTransaction();
+            checkCandidates();
+            // Each execute call gets its own copy of paramtab and vartab.
+            // This allows multiple execution of the same query in parallel.
+            ParameterTable params = paramtab.getCopy();
+            params.initValueHandling();
+            params.checkUnboundParams();
+            VariableTable vars = vartab.getCopy();
+            vars.initValueHandling();
+            StoreManager srm = pm.getStoreManager();
+            QueryResult queryResult = 
+                srm.newQueryResult(new QueryResultHelperImpl(
+                    pm, compiledTree, candidates, params, vars));
+            openQueryResults.add(queryResult);
+            return queryResult;
+        }
+    }
+    
+    /** 
+     *  Execute the query and return the filtered Collection.
+     * @return the filtered Collection.
+     * @see #executeWithArray(Object[] parameters)
+     * @param p1 the value of the first parameter declared.
+     */
+    public Object execute(Object p1)
+    {
+        Object[] params = new Object[1];
+        params[0] = p1;
+        return executeWithArray(params);
+    }
+    
+    /** 
+     * Execute the query and return the filtered Collection.
+     * @return the filtered Collection.
+     * @see #executeWithArray(Object[] parameters)
+     * @param p1 the value of the first parameter declared.
+     * @param p2 the value of the second parameter declared.
+     */
+    public Object execute(Object p1, Object p2)
+    {
+        Object[] params = new Object[2];
+        params[0] = p1;
+        params[1] = p2;
+        return executeWithArray(params);
+    }
+    
+    /** 
+     * Execute the query and return the filtered Collection.
+     * @return the filtered Collection.
+     * @see #executeWithArray(Object[] parameters)
+     * @param p1 the value of the first parameter declared.
+     * @param p2 the value of the second parameter declared.
+     * @param p3 the value of the third parameter declared.
+     */
+    public Object execute(Object p1, Object p2, Object p3)
+    {
+        Object[] params = new Object[3];
+        params[0] = p1;
+        params[1] = p2;
+        params[2] = p3;
+        return executeWithArray(params);
+    }
+    
+    /** 
+     * Execute the query and return the filtered Collection.
+     * @return the filtered Collection.
+     * @see #executeWithArray(Object[] parameters)
+     * @param parameters the Map containing all of the parameters.
+     */
+    public Object executeWithMap(Map parameters)
+    {
+        synchronized (this.paramtab)
+        {
+            compile();
+            pm.assertIsOpen();
+            checkTransaction();
+            checkCandidates();
+            // Each execute call gets its own copy of paramtab and vartab.
+            // This allows multiple execution of the same query in parallel.
+            ParameterTable params = paramtab.getCopy();
+            params.initValueHandling();
+            params.setValues(pm, parameters);
+            params.checkUnboundParams();
+            VariableTable vars = vartab.getCopy();
+            vars.initValueHandling();
+            StoreManager srm = pm.getStoreManager();
+            QueryResult queryResult = 
+                srm.newQueryResult(new QueryResultHelperImpl(
+                    pm, compiledTree, candidates, params, vars));
+            openQueryResults.add(queryResult);
+            return queryResult;
+        }
+    }
+
+    /** Execute the query and return the filtered Collection.
+     *
+     * <P>The execution of the query obtains the values of the parameters and
+     * matches them against the declared parameters in order.  The names
+     * of the declared parameters are ignored.  The type of
+     * the declared parameters must match the type of the passed parameters,
+     * except that the passed parameters might need to be unwrapped to get
+     * their primitive values.
+     *
+     * <P>The filter, import, declared parameters, declared variables, and
+     * ordering statements are verified for consisten1cy.
+     *
+     * <P>Each element in the candidate Collection is examined to see that it
+     * is assignment compatible to the Class of the query.  It is then evaluated
+     * by the boolean expression of the filter.  The element passes the filter
+     * if there exist unique values for all variables for which the filter
+     * expression evaluates to true.
+     * @return the filtered Collection.
+     * @param parameters the Object array with all of the parameters.
+     */
+    public Object executeWithArray(Object[] parameters)
+    {
+        synchronized (this.paramtab)
+        {
+            compile();
+            pm.assertIsOpen();
+            checkTransaction();
+            checkCandidates();
+            // Each execute call gets its own copy of paramtab and vartab.
+            // This allows multiple execution of the same query in parallel.
+            ParameterTable params = paramtab.getCopy();
+            params.initValueHandling();
+            params.setValues(pm, parameters);
+            params.checkUnboundParams();
+            VariableTable vars = vartab.getCopy();
+            vars.initValueHandling();
+            StoreManager srm = pm.getStoreManager();
+            QueryResult queryResult = 
+                srm.newQueryResult(new QueryResultHelperImpl(
+                    pm, compiledTree, candidates, params, vars));
+            openQueryResults.add(queryResult);
+            return queryResult;
+        }
+    }
+    
+    /** 
+     * Get the PersistenceManager associated with this Query.
+     *
+     * <P>If this Query was restored from a serialized form, it has no 
+     * PersistenceManager, and this method returns null.
+     * @return the PersistenceManager associated with this Query.
+     */
+    public PersistenceManager getPersistenceManager()
+    {
+        return (pm == null) ? null : pm.getCurrentWrapper();
+    }
+  
+    /** 
+     * Close a query result and release any resources associated with it.  The
+     * parameter is the return from execute(...) and might have iterators open 
+     * on it. Iterators associated with the query result are invalidated: they 
+     * return false to hasNext() and throw NoSuchElementException to next().
+     * @param queryResult the result of execute(...) on this Query instance.
+     */    
+    public void close (Object queryResult)
+    {
+        if (queryResult instanceof QueryResult) {
+            openQueryResults.remove(queryResult);
+            ((QueryResult)queryResult).close();
+        }
+    }
+    
+    /** 
+     * Close all query results associated with this Query instance, and release
+     * all resources associated with them.  The query results might have 
+     * iterators open on them.  Iterators associated with the query results are 
+     * invalidated: they return false to hasNext() and 
+     * throw NoSuchElementException to next().
+     */    
+    public void closeAll ()
+    {
+        for(Iterator i = openQueryResults.iterator(); i.hasNext();) {
+            QueryResult queryResult = (QueryResult)i.next();
+            queryResult.close();
+        }
+        openQueryResults.clear();
+    }
+
+    //========= Internal helper methods ==========
+    
+    /** 
+     * This method verifies that if there is no transaction in progress then 
+     * the NontransactionalRead flag must be set to true.
+     */
+    private void checkTransaction() 
+    {
+        Transaction tx = pm.currentTransaction();
+        if ((!tx.isActive()) & !tx.getNontransactionalRead() )
+                throw new JDOQueryException(msg.msg("EXC_NoTransaction")); //NOI18N
+    }
+    
+    /**
+     * This method checks a valid candidates setting for this query. 
+     */
+    private void checkCandidates()
+    {
+        if (candidates == null) {
+            if (queryTree != null) {
+                candidates = pm.getExtent(queryTree.getCandidateClass(), true);
+            }
+            else if (candidateClass != null) {
+                candidates = pm.getExtent(candidateClass, true);
+            }
+            else {
+                throw new JDOQueryException(msg.msg("EXC_MissingCandidateClass")); //NOI18N
+            }
+        }
+    }
+
+    /**
+     * This method checks the candidate class of the underlying query
+     * tree. If this query instance was created from a query tree, and 
+     * subsequently serialized and deserialized then The class instance of
+     * the candidate class is not set. The class instance of the candidate
+     * class is not part of the serialized state of a querty tree; only the
+     * name gets stored. In this case the method uses the PM algorithm to
+     * calculate the class instance of the candidate class and stores it in
+     * the query tree. 
+     */
+    private void checkQueryTreeCandidateClass()
+    {
+        if (queryTree == null) 
+            return;
+
+        if (queryTree.getCandidateClass() == null) {
+            String candidateClassName = 
+                queryTree.getSerializedCandidateClassName();
+            if (candidateClassName != null) {
+                try {
+                    queryTree.setCandidateClass(
+                        pm.loadClass(candidateClassName, null));
+                }
+                catch (ClassNotFoundException ex) {
+                    throw new JDOQueryException(
+                        msg.msg("EXC_UnknownCandidateClass", //NOI18N
+                                candidateClassName), ex);
+                }
+            }
+        }
+    }
+
+    /** Serialization support. */
+    private void readObject(java.io.ObjectInputStream in)
+        throws java.io.IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+        this.openQueryResults = new HashSet();
+    }
+
+    /** Deserialization support. */
+    private void writeObject(java.io.ObjectOutputStream out)
+        throws IOException
+    {
+        if (candidateClass != null)
+            this.candidateClassName = candidateClass.getName();
+        out.defaultWriteObject();
+    }
+}

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryResultHelperImpl.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryResultHelperImpl.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryResultHelperImpl.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/QueryResultHelperImpl.java Sun May 22 11:08:57 2005
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * QueryResultHelperImpl.java
+ *
+ * Created on August 31, 2001
+ */
+
+package org.apache.jdo.impl.jdoql;
+
+import java.util.*;
+
+import javax.jdo.Extent;
+import javax.jdo.PersistenceManager;
+import javax.jdo.JDOHelper;
+import javax.jdo.JDOUserException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.impl.jdoql.jdoqlc.JDOQLAST;
+import org.apache.jdo.impl.jdoql.scope.ParameterTable;
+import org.apache.jdo.impl.jdoql.scope.VariableTable;
+import org.apache.jdo.query.QueryResultHelper;
+import org.apache.jdo.jdoql.tree.Expression;
+import org.apache.jdo.jdoql.tree.QueryTree;
+import org.apache.jdo.jdoql.tree.TreeWalker;
+import org.apache.jdo.jdoql.tree.ValueTable;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+/** 
+ * This class implements the helper interface to support the query 
+ * execution strategy of the StoreManager.   When a query is executed, 
+ * the filter is parsed.  The parsed query, candidate collection or extent,
+ * and actual parameters of the execute are stored in the
+ * QueryResultHelper.
+ *
+ * @author Michael Bouschen
+ */
+public class QueryResultHelperImpl
+    implements QueryResultHelper 
+{
+    /** The query PM */
+    private PersistenceManagerInternal pm;
+
+    /** The query tree. */
+    private QueryTree queryTree;
+
+    /** The candidates for this query evalutaion. */
+    private Object candidates;
+
+    /** The table of parameter values. */
+    private ParameterTable parameters;
+
+    /** The table of variable values. */
+    private VariableTable variables;
+
+    /** The memory query evaluator. */
+    private MemoryQuery eval;
+
+    /** The tree walker used when applying the filter and do the ordering. */
+    private TreeWalker treeWalker;
+
+    /** The candidate class taken from the queryTree. */
+    private Class candidateClass;
+
+    /** The ordering comparator. */
+    private OrderingComparator ordering;
+    
+    /** Logger */
+    private static Log logger = LogFactory.getFactory().getInstance(
+        "org.apache.jdo.impl.jdoql"); //NOI18N
+
+    /** I18N support */
+    protected final static I18NHelper msg =  
+        I18NHelper.getInstance(QueryResultHelperImpl.class);
+ 
+    /**
+     *
+     */
+    public QueryResultHelperImpl(PersistenceManagerInternal pm,
+                                 QueryTree queryTree, Object candidates, 
+                                 ParameterTable parameters, VariableTable variables)
+    {
+        this.pm = pm;
+        this.queryTree = queryTree;
+        this.candidates = candidates;
+        this.parameters = parameters;
+        this.variables = variables;
+        this.candidateClass = queryTree.getCandidateClass();
+        this.eval = new MemoryQuery(pm, parameters, variables);
+        this.treeWalker = new TreeWalker();
+        this.ordering = new OrderingComparator(treeWalker, eval);
+        if (logger.isTraceEnabled()) {
+            String repr = null;
+            if (queryTree == null)
+                repr = "null"; //NOI18N
+            else if (queryTree instanceof JDOQLAST)
+                repr = ((JDOQLAST)queryTree).treeToString();
+            else
+                repr = queryTree.toString();
+            logger.trace("QueryTree\n" + repr); //NOI18N
+        }
+    }
+
+    /** Return the candidate Collection or Extent specified by
+     * the user.
+     * @return the candidate Collection or Extent.
+     */
+    public Object getCandidates()
+    {
+        return candidates;
+    }
+        
+    /** This method filters the specified collection, removing all elements that
+     * are not assignment compatible to the candidate Class specified by the 
+     * user, and then orders the results according to the ordering expression 
+     * specified by the user.  A new List is returned.
+     * @param candidates the collection of instances to be filtered and ordered
+     * @return the filtered parameter collection ordered by the ordering 
+     * expression.
+     */    
+    public List orderCandidates(Collection candidates)
+    {
+        List list = new ArrayList();
+        for (Iterator i = candidates.iterator(); i.hasNext();) {
+            Object next = i.next();
+            if (candidateClass.isInstance(next))
+                list.add(next);
+        }
+        ordering.setQueryTree(queryTree);
+        Collections.sort(list, ordering);
+        if (logger.isTraceEnabled())
+            logger.trace("orderCandidates -> " + list); //NOI18N
+        return list;
+    }
+    
+    /** This method determines whether the specified object is assignment 
+     * compatible to the candidate Class specified by the user and satisfies 
+     * the query filter.
+     * @return <CODE>true</CODE> if the specified object is of the candidate 
+     * class and satisfies the query filter; <CODE>false otherwise</CODE>
+     * @param obj the candidate object.
+     */    
+    public boolean applyFilter (Object obj)
+    {
+        boolean satisfies = false;
+        if (candidateClass.isInstance(obj)) {
+            // check whether obj is bound to the same pm as the one from the query
+            checkPM(pm, obj);
+            eval.setCurrent(obj);
+            Object result = treeWalker.walk(queryTree.getFilter(), eval);
+            satisfies = ((result instanceof Boolean) && ((Boolean)result).booleanValue());
+        }
+        if (logger.isTraceEnabled())
+            logger.trace("applyFilter -> " + satisfies + "\t" + obj); //NOI18N
+        return satisfies;
+    }
+    
+    /** Return the query tree which is either specified by the user or compiled 
+     * from a JDOQL query.
+     * @return the query tree
+     */
+    public QueryTree getQueryTree()
+    {
+        return queryTree;
+    }
+    
+    /** This method returns the parameter values passed by the user
+     * in the execute(...) method.
+     * @return a ValueTable representing the parameter values
+     */
+    public ValueTable getParameterValues()
+    {
+        return parameters;
+    }
+
+    //========= Helper method ==========
+
+    /**
+     * Checks the PersistenceManager of the specified value to be 
+     * identical to the one from the query instance.
+     */
+    public static void checkPM(PersistenceManagerInternal queryPM, Object value)
+    {
+        if (value instanceof Collection) {
+            // iterate collection and call checkPM for all elements
+            for (Iterator i = ((Collection)value).iterator(); i.hasNext();)
+                checkPM(queryPM, i.next());
+        }
+        else if (value instanceof Object[]) {
+            // iterate array and call checkPM for all elements
+            // No need to check array of primitive types
+            Object[] array = (Object[])value;
+            for (int i = 0; i < array.length; i++)
+                checkPM(queryPM, array[i]);
+        }
+        else
+        {
+            PersistenceManager instancePM = 
+                JDOHelper.getPersistenceManager(value);
+            if ((instancePM != null) && !instancePM.equals(queryPM)) {
+                // instancePM is NOT the one from the query => exception
+                throw new JDOUserException(
+                    msg.msg("EXC_InstanceBoundToDifferentPM", value)); //NOI18N
+            }
+        }
+    }
+        
+}
+

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/ErrorMsg.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/ErrorMsg.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/ErrorMsg.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/ErrorMsg.java Sun May 22 11:08:57 2005
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * ErrorMsg.java
+ *
+ * Created on August 28, 2001
+ */
+
+package org.apache.jdo.impl.jdoql.jdoqlc;
+
+import java.util.ResourceBundle;
+
+import javax.jdo.JDOFatalInternalException;
+import javax.jdo.JDOUnsupportedOptionException;
+
+import org.apache.jdo.jdoql.JDOQueryException;
+import org.apache.jdo.util.I18NHelper;
+
+
+/** 
+ * 
+ * @author  Michael Bouschen
+ */
+public class ErrorMsg
+{
+    /** 
+     * The context is included in an error message. It usually defines the query 
+     * method with the invalid definition (such as declareParameters, setFilter, 
+     * etc.).
+     */
+    protected String context = null;
+    
+    /** I18N support */
+    protected final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", ErrorMsg.class.getClassLoader()); //NOI18N
+    
+    /** Return the current context string */
+    public String getContext()
+    {
+        return context;
+    }
+    
+    /** Set the specified string as the current context string. */
+    public void setContext(String name)
+    {
+        context = name;
+    }
+
+    /**
+     * Indicates an error situation. 
+     * @param line line number
+     * @param col column number
+     * @param text error message
+     */
+    public void error(int line, int col, String text)
+        throws JDOQueryException
+    {
+        if (line > 1) {
+            // include line and column info
+            Object args[] = {context, new Integer(line), new Integer(col), text};
+            throw new JDOQueryException(
+                msg.msg("EXC_PositionInfoMsgLineColumn", args)); //NOI18N
+        }
+        else if (col > 0)
+        {
+            // include column info
+            Object args[] = {context, new Integer(col), text};
+            throw new JDOQueryException(
+                msg.msg("EXC_PositionInfoMsgColumn", args)); //NOI18N
+        }
+        else 
+        {
+            Object args[] = {context, text};
+            throw new JDOQueryException(
+                msg.msg("EXC_PositionInfoMsg", args)); //NOI18N
+        }
+    }
+    
+    /**
+     * Indicates that a feature is not supported by the current release. 
+     * @param line line number
+     * @param col column number
+     * @param text message
+     */
+    public void unsupported(int line, int col, String text)
+        throws JDOUnsupportedOptionException
+    {
+        if (line > 1)
+        {
+            // include line and column info
+            Object args[] = {context, new Integer(line), new Integer(col), text};
+            throw new JDOUnsupportedOptionException(
+                msg.msg("EXC_PositionInfoMsgLineColumn", args)); //NOI18N
+        }
+        else if (col > 0)
+        {
+            // include column info
+            Object args[] = {context, new Integer(col), text};
+            throw new JDOUnsupportedOptionException(
+                msg.msg("EXC_PositionInfoMsgColumn", args)); //NOI18N
+        }
+        else 
+        {
+            Object args[] = {context, text};
+            throw new JDOUnsupportedOptionException(
+                msg.msg("EXC_PositionInfoMsg", args)); //NOI18N
+        }   
+    }
+    
+    /**
+     * Indicates a fatal situation (implementation error).
+     * @param text error message
+     */
+    public void fatal(String text)
+        throws JDOFatalInternalException
+    {
+        throw new JDOFatalInternalException(text);
+    }
+
+    /**
+     * Indicates a fatal situation (implementation error).
+     * @param text error message
+     */
+    public void fatal(String text, Exception nested)
+        throws JDOFatalInternalException
+    {
+        throw new JDOFatalInternalException(text, nested);
+    }
+}

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQL.g
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQL.g?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQL.g (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQL.g Sun May 22 11:08:57 2005
@@ -0,0 +1,843 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * JDOQL.g
+ *
+ * Created on August 28, 2001
+ */
+
+header
+{
+    package org.apache.jdo.impl.jdoql.jdoqlc;
+
+    import antlr.MismatchedTokenException;
+    import antlr.MismatchedCharException;
+    import antlr.NoViableAltException;
+    import antlr.NoViableAltForCharException;
+    import antlr.TokenStreamRecognitionException;
+    
+    import org.apache.jdo.jdoql.JDOQueryException;
+    import org.apache.jdo.impl.jdoql.tree.*;
+    import org.apache.jdo.util.I18NHelper;
+}
+
+//===== Lexical Analyzer Class Definitions =====
+
+/**
+ * This class defines the lexical analysis for the JDOQL compiler.
+ *
+ * @author  Michael Bouschen
+ */
+class JDOQLLexer extends Lexer;
+options
+{
+    k = 2;
+    exportVocab = JDOQL;
+    charVocabulary = '\u0000'..'\uFFFE'; //NOI18N
+}
+
+tokens {
+
+    IMPORT = "import"         <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    IMPORT_ON_DEMAND          <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>;
+    THIS = "this"             <AST=org.apache.jdo.impl.jdoql.tree.ThisExpr>; //NOI18N
+    ASCENDING = "ascending"   <AST=org.apache.jdo.impl.jdoql.tree.AscendingOrderingExpr>; //NOI18N
+    DESCENDING = "descending" <AST=org.apache.jdo.impl.jdoql.tree.DescendingOrderingExpr>; //NOI18N
+    
+    // types
+    
+    BOOLEAN = "boolean"       <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    BYTE = "byte"             <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    CHAR = "char"             <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    SHORT = "short"           <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    INT = "int"               <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    FLOAT = "float"           <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    LONG = "long"             <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    DOUBLE = "double"         <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>; //NOI18N
+    
+    // literals
+    
+    NULL = "null"   <AST=org.apache.jdo.impl.jdoql.tree.ConstantExpr>; //NOI18N
+    TRUE = "true"   <AST=org.apache.jdo.impl.jdoql.tree.BooleanLiteralExpr>; //NOI18N
+    FALSE = "false" <AST=org.apache.jdo.impl.jdoql.tree.BooleanLiteralExpr>; //NOI18N
+
+    // other tokens
+
+    EQUAL     <AST=org.apache.jdo.impl.jdoql.tree.EqualsExpr>;
+    NOT_EQUAL <AST=org.apache.jdo.impl.jdoql.tree.NotEqualsExpr>;
+    GE        <AST=org.apache.jdo.impl.jdoql.tree.GreaterThanEqualsExpr>;
+    GT        <AST=org.apache.jdo.impl.jdoql.tree.GreaterThanExpr>;
+    LE        <AST=org.apache.jdo.impl.jdoql.tree.LessThanEqualsExpr>;
+    LT        <AST=org.apache.jdo.impl.jdoql.tree.LessThanExpr>;
+
+    PLUS      <AST=org.apache.jdo.impl.jdoql.tree.PlusExpr>;
+    MINUS     <AST=org.apache.jdo.impl.jdoql.tree.MinusExpr>;
+    STAR      <AST=org.apache.jdo.impl.jdoql.tree.TimesExpr>;
+    DIV       <AST=org.apache.jdo.impl.jdoql.tree.DivideExpr>;
+
+    BOR       <AST=org.apache.jdo.impl.jdoql.tree.OrExpr>;
+    OR        <AST=org.apache.jdo.impl.jdoql.tree.ConditionalOrExpr>;
+    BAND      <AST=org.apache.jdo.impl.jdoql.tree.AndExpr>;
+    AND       <AST=org.apache.jdo.impl.jdoql.tree.ConditionalAndExpr>;
+    LNOT      <AST=org.apache.jdo.impl.jdoql.tree.NotExpr>;
+    BNOT      <AST=org.apache.jdo.impl.jdoql.tree.ComplementExpr>;
+
+    INT_LITERAL    <AST=org.apache.jdo.impl.jdoql.tree.IntLiteralExpr>;
+    LONG_LITERAL   <AST=org.apache.jdo.impl.jdoql.tree.IntLiteralExpr>;
+    FLOAT_LITERAL  <AST=org.apache.jdo.impl.jdoql.tree.FloatLiteralExpr>;
+    DOUBLE_LITERAL <AST=org.apache.jdo.impl.jdoql.tree.DoubleLiteralExpr>;
+    CHAR_LITERAL   <AST=org.apache.jdo.impl.jdoql.tree.CharLiteralExpr>;
+    STRING_LITERAL <AST=org.apache.jdo.impl.jdoql.tree.ConstantExpr>;
+    IDENT          <AST=org.apache.jdo.impl.jdoql.tree.IdentifierExpr>;
+
+    DOT <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>;
+
+    // lexer only
+
+    LPAREN;
+    RPAREN;
+    COMMA;
+    SEMI;
+    WS;
+    NEWLINE;
+    ESC; 
+    HEX_DIGIT;
+    EXPONENT;
+    FLOATINGPOINT_SUFFIX;
+    UNICODE_ESCAPE;
+    UNICODE_CHAR;
+}
+
+{
+    /** The error message support class. */
+    protected ErrorMsg errorMsg;
+    
+    /** The width of a tab stop. */
+    protected static final int TABSIZE = 4;
+
+    /** */
+    protected static final int EOF_CHAR = 65535; // = (char) -1 = EOF
+
+    /** I18N support. */
+    protected static final I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", JDOQLLexer.class.getClassLoader()); //NOI18N
+    
+    /**
+     *
+     */
+    public void init(ErrorMsg errorMsg)
+    {
+        this.errorMsg = errorMsg;
+    }
+    
+    /**
+     *
+     */
+    public void tab() 
+    {
+        int column = getColumn();
+        int newColumn = (((column-1)/TABSIZE)+1)*TABSIZE+1;
+        setColumn(newColumn);
+    }
+
+    /**
+     *
+     */
+    public void reportError(int line, int column, String s)
+    {
+        errorMsg.error(line, column, s);
+    }
+
+    /**
+     * Report lexer exception errors caught in nextToken()
+     */
+    public void reportError(RecognitionException e)
+    {
+        handleANTLRException(e, errorMsg);
+    }
+
+    /**
+     * Lexer error-reporting function
+     */
+    public void reportError(String s)
+    {
+        errorMsg.error(0, 0, s);
+    }
+
+    /**
+     * Lexer warning-reporting function
+     */
+    public void reportWarning(String s)
+    {
+        throw new JDOQueryException(s);
+    }
+
+    /**
+     *
+     */
+    public static void handleANTLRException(ANTLRException ex, ErrorMsg errorMsg)
+    {
+        if (ex instanceof MismatchedCharException) {
+            MismatchedCharException mismatched = (MismatchedCharException)ex;
+            if (mismatched.mismatchType == MismatchedCharException.CHAR) {
+                if (mismatched.foundChar == EOF_CHAR) {
+                    errorMsg.error(mismatched.getLine(), mismatched.getColumn(), 
+                        msg.msg("EXC_UnexpectedEOF")); //NOI18N
+                }
+                else {
+                    errorMsg.error(mismatched.getLine(), mismatched.getColumn(), 
+                        msg.msg("EXC_ExpectedCharFound", //NOI18N
+                            String.valueOf((char)mismatched.expecting), 
+                            String.valueOf((char)mismatched.foundChar)));
+                }
+                return;
+            }
+        }
+        else if (ex instanceof MismatchedTokenException) {
+            MismatchedTokenException mismatched = (MismatchedTokenException)ex;
+            Token token = mismatched.token;
+            if ((mismatched.mismatchType == MismatchedTokenException.TOKEN) &&
+                (token != null)) {
+                if (token.getType() == Token.EOF_TYPE) {
+                    errorMsg.error(token.getLine(), token.getColumn(), 
+                        msg.msg("EXC_UnexpectedEOF")); //NOI18N
+                }
+                else {
+                    errorMsg.error(token.getLine(), token.getColumn(), 
+                        msg.msg("EXC_SyntaxErrorAt", token.getText())); //NOI18N
+                }
+                return;
+            }
+        }
+        else if (ex instanceof NoViableAltException) {
+            Token token = ((NoViableAltException)ex).token;
+            if (token != null) {
+                if (token.getType() == Token.EOF_TYPE) {
+                    errorMsg.error(token.getLine(), token.getColumn(), 
+                        msg.msg("EXC_UnexpectedEOF")); //NOI18N
+                }
+                else {
+                    errorMsg.error(token.getLine(), token.getColumn(), 
+                        msg.msg("EXC_UnexpectedToken", token.getText())); //NOI18N
+                }
+                return;
+            }
+        }
+        else if (ex instanceof NoViableAltForCharException) {
+            NoViableAltForCharException noViableAlt = (NoViableAltForCharException)ex;
+            errorMsg.error(noViableAlt.getLine(), noViableAlt.getColumn(), 
+                msg.msg("EXC_UnexpectedChar", String.valueOf((char)noViableAlt.foundChar)));//NOI18N
+        }
+        else if (ex instanceof TokenStreamRecognitionException) {
+            handleANTLRException(((TokenStreamRecognitionException)ex).recog, errorMsg);
+        }
+
+        // no special handling from aboves matches the exception if this line is reached =>
+        // make it a syntax error
+        int line = 0;
+        int column = 0;
+        if (ex instanceof RecognitionException) {
+            line = ((RecognitionException)ex).getLine();
+            column = ((RecognitionException)ex).getColumn();
+        }
+        errorMsg.error(line, column, msg.msg("EXC_SyntaxError")); //NOI18N
+    }
+}
+
+// OPERATORS
+
+// The following Java operators are included although not supported by JDOQL:
+//   ASSIGN, DIV_ASSIGN, PLUS_ASSIGN, INC, MINUS_ASSIGN, DEC, STAR_ASSIGN, 
+//   SR, SL, BOR_ASSIGN, BAND_ASSIGN
+// The lexer recognizes them, but the parser will result in a syntax error.
+// This gurantees an error message. Othewise the java operator pre-decrement
+// is mapped to two unray minus. Two unray minus are valid in JDOQL, but not 
+// indented.
+
+LPAREN          :   '('     ;
+RPAREN          :   ')'     ;
+COMMA           :   ','     ;
+//DOT           :   '.'     ;
+ASSIGN          :   "="     ; //NOI18N
+EQUAL           :   "=="    ; //NOI18N
+LNOT            :   '!'     ;
+BNOT            :   '~'     ;
+NOT_EQUAL       :   "!="    ; //NOI18N
+DIV             :   '/'     ;
+DIV_ASSIGN      :   "/="    ; //NOI18N
+PLUS            :   '+'     ;
+PLUS_ASSIGN     :   "+="    ; //NOI18N
+INC             :   "++"    ; //NOI18N
+MINUS           :   '-'     ;
+MINUS_ASSIGN    :   "-="    ; //NOI18N
+DEC             :   "--"    ; //NOI18N
+STAR            :   '*'     ;
+STAR_ASSIGN     :   "*="    ; //NOI18N
+SR              :   ">>"    ; //NOI18N
+GE              :   ">="    ; //NOI18N
+GT              :   ">"     ; //NOI18N
+SL              :   "<<"    ; //NOI18N
+LE              :   "<="    ; //NOI18N
+LT              :   '<'     ;
+BOR             :   '|'     ;
+BOR_ASSIGN      :   "|="    ; //NOI18N
+OR              :   "||"    ; //NOI18N
+BAND            :   '&'     ;
+BAND_ASSIGN     :   "&="    ; //NOI18N
+AND             :   "&&"    ; //NOI18N
+SEMI            :   ';'     ;
+
+// Whitespace -- ignored
+WS
+    :   (   ' '
+        |   '\t'
+        |   '\f'
+        )+
+        { _ttype = Token.SKIP; }
+    ;
+
+NEWLINE
+    :   (   "\r\n"  //NOI18N
+        |   '\r'
+        |   '\n'
+        )
+        { 
+            newline(); 
+            _ttype = Token.SKIP; 
+        }
+    ;
+
+// character literals
+CHAR_LITERAL
+    :   '\'' ( ESC | ~'\'' ) '\'' 
+    ;
+
+// string literals
+STRING_LITERAL
+    :  '"' ( ESC | ~'"')* '"' //NOI18N
+    ;
+
+protected
+ESC
+    :   '\\'
+        (   'n'
+        |   'r'
+        |   't'
+        |   'b'
+        |   'f'
+        |   '"' //NOI18N
+        |   '\''
+        |   '\\'
+        |   ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT 
+        |   ('0'..'3')
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :   ('0'..'7')
+                (   
+                    options {
+                        warnWhenFollowAmbig = false;
+                    }
+                :   '0'..'7'
+                )?
+            )?
+        |   ('4'..'7')
+            (
+                options {
+                    warnWhenFollowAmbig = false;
+                }
+            :   ('0'..'9')
+            )?
+        )
+    ;
+
+protected
+HEX_DIGIT
+    :   ('0'..'9'|'A'..'F'|'a'..'f')
+    ;
+
+INT_LITERAL
+    {   
+        boolean isDecimal=false;
+        int tokenType = DOUBLE_LITERAL; 
+    }
+    :   '.' {_ttype = DOT;}
+            (('0'..'9')+ {tokenType = DOUBLE_LITERAL;}
+             (EXPONENT)? 
+             (tokenType = FLOATINGPOINT_SUFFIX)? 
+            { _ttype = tokenType; })?
+    |   (   '0' {isDecimal = true;} // special case for just '0'
+            (   ('x'|'X')
+                (
+                    options {
+                        warnWhenFollowAmbig=false;
+                    }
+                :   HEX_DIGIT
+                )+
+            |   ('0'..'7')+
+            )?
+        |   ('1'..'9') ('0'..'9')*  {isDecimal=true;}
+        )
+        (   ('l'|'L') { _ttype = LONG_LITERAL; }
+        |   {isDecimal}?
+            {tokenType = DOUBLE_LITERAL;} 
+            (   '.' ('0'..'9')* (EXPONENT)? 
+                (tokenType = FLOATINGPOINT_SUFFIX)?
+            |   EXPONENT (tokenType = FLOATINGPOINT_SUFFIX)?
+            |   tokenType = FLOATINGPOINT_SUFFIX
+            )
+            { _ttype = tokenType; }
+        )?
+    ;
+
+protected
+EXPONENT
+    :   ('e'|'E') ('+'|'-')? ('0'..'9')+
+    ;
+
+protected
+FLOATINGPOINT_SUFFIX returns [int tokenType]
+    : 'f' { tokenType = FLOAT_LITERAL; } 
+    | 'F' { tokenType = FLOAT_LITERAL; } 
+    | 'd' { tokenType = DOUBLE_LITERAL; } 
+    | 'D' { tokenType = DOUBLE_LITERAL; } 
+    ;
+
+IDENT
+    options {paraphrase = "an identifier"; testLiterals=true;} //NOI18N
+    :   (   'a'..'z'
+        |   'A'..'Z'
+        |   '_'
+        |   '$'
+        |   UNICODE_ESCAPE
+        |   c1:'\u0080'..'\uFFFE'
+            { 
+                if (!Character.isJavaIdentifierStart(c1)) {
+                    errorMsg.error(getLine(), getColumn(), 
+                        msg.msg("EXC_UnexpectedChar", String.valueOf(c1)));//NOI18N
+                }
+            }
+        ) 
+        (   'a'..'z'
+        |   'A'..'Z'
+        |   '_'
+        |   '$'
+        |   '0'..'9'
+        |   UNICODE_ESCAPE
+        |   c2:'\u0080'..'\uFFFE'
+            {   
+                if (!Character.isJavaIdentifierPart(c2)) {
+                    errorMsg.error(getLine(), getColumn(), 
+                        msg.msg("EXC_UnexpectedChar", String.valueOf(c2)));//NOI18N
+                }
+            }
+        )*
+    ;
+
+protected
+UNICODE_ESCAPE
+    : '\\' ('u')+ HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
+        {
+            try {
+                String tmp = text.toString();
+                char c  = (char)Integer.parseInt(tmp.substring(tmp.length() - 4, tmp.length()), 16);
+                // problems using ANTLR feature $setText => use generated code
+                text.setLength(_begin); 
+                text.append(new Character(c).toString());
+            }
+            catch (NumberFormatException ex) {
+                errorMsg.fatal(msg.msg("ERR_UnexpectedExceptionUnicode"), ex); //NOI18N
+            }
+        }
+    ;
+
+//===== Parser Class Definitions =====
+
+/**
+ * This class defines the syntax analysis (parser) of the JDOQL compiler.
+ *
+ * @author  Michael Bouschen
+ */
+class JDOQLParser extends Parser;
+
+options {
+    k = 2;                   // two token lookahead
+    exportVocab = JDOQL;
+    buildAST = true;
+    ASTLabelType = "JDOQLAST"; // NOI18N
+}
+
+tokens
+{
+    // "imaginary" tokens, that have no corresponding real input
+
+    QUERY_TREE             <AST=org.apache.jdo.impl.jdoql.tree.Tree>;
+    CANDIDATE_CLASS        <AST=org.apache.jdo.impl.jdoql.tree.CandidateClassImpl>;
+    PARAMETER_DECL         <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>;
+    VARIABLE_DECL          <AST=org.apache.jdo.impl.jdoql.tree.VariableDecl>;
+
+    // operators
+    OBJECT_EQUAL           <AST=org.apache.jdo.impl.jdoql.tree.EqualsExpr>;
+    OBJECT_NOT_EQUAL       <AST=org.apache.jdo.impl.jdoql.tree.NotEqualsExpr>;
+    COLLECTION_EQUAL       <AST=org.apache.jdo.impl.jdoql.tree.EqualsExpr>;
+    COLLECTION_NOT_EQUAL   <AST=org.apache.jdo.impl.jdoql.tree.NotEqualsExpr>;
+    UNARY_MINUS            <AST=org.apache.jdo.impl.jdoql.tree.UnaryMinusExpr>;
+    UNARY_PLUS             <AST=org.apache.jdo.impl.jdoql.tree.UnaryPlusExpr>;
+    CONCAT                 <AST=org.apache.jdo.impl.jdoql.tree.PlusExpr>;
+    CAST                   <AST=org.apache.jdo.impl.jdoql.tree.CastExpr>;
+
+    // special dot expressions
+    FIELD_ACCESS           <AST=org.apache.jdo.impl.jdoql.tree.FieldAccessExpr>;
+    STATIC_FIELD_ACCESS    <AST=org.apache.jdo.impl.jdoql.tree.FieldAccessExpr>;
+    NAVIGATION             <AST=org.apache.jdo.impl.jdoql.tree.FieldAccessExpr>;
+    CONTAINS               <AST=org.apache.jdo.impl.jdoql.tree.ContainsCallExpr>;
+    STARTS_WITH            <AST=org.apache.jdo.impl.jdoql.tree.StartsWithCallExpr>;
+    ENDS_WITH              <AST=org.apache.jdo.impl.jdoql.tree.EndsWithCallExpr>;
+    IS_EMPTY               <AST=org.apache.jdo.impl.jdoql.tree.IsEmptyCallExpr>;
+    
+    // identifier types
+    VARIABLE_ACCESS        <AST=org.apache.jdo.impl.jdoql.tree.VariableAccessExpr>;
+    PARAMETER_ACCESS       <AST=org.apache.jdo.impl.jdoql.tree.ParameterAccessExpr>;
+
+    // types
+    TYPE                   <AST=org.apache.jdo.impl.jdoql.tree.TypeImpl>;
+
+    // constant value
+    CONSTANT               <AST=org.apache.jdo.impl.jdoql.tree.ConstantExpr>;
+
+    // Query Tree nodes
+    BOOLEAN_LITERAL        <AST=org.apache.jdo.impl.jdoql.tree.BooleanLiteralExpr>;
+    BYTE_LITERAL           <AST=org.apache.jdo.impl.jdoql.tree.ByteLiteralExpr>;
+    SHORT_LITERAL          <AST=org.apache.jdo.impl.jdoql.tree.ShortLiteralExpr>;
+
+    // temporary node removed by Semantic
+    ARG_LIST               <AST=org.apache.jdo.impl.jdoql.tree.NodeImpl>;
+}
+
+{
+    /** The error message support class. */
+    protected ErrorMsg errorMsg;
+    
+    /** I18N support. */
+    protected final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", JDOQLParser.class.getClassLoader()); //NOI18N
+    
+    /**
+     *
+     */
+    public void init(ErrorMsg errorMsg)
+    {
+        this.errorMsg = errorMsg;
+    }
+    
+    /**
+     * ANTLR method called when an error was detected.
+     */
+    public void reportError(RecognitionException ex)
+    {
+        JDOQLLexer.handleANTLRException(ex, errorMsg);
+    }
+
+    /**
+     * ANTLR method called when an error was detected.
+     */
+    public void reportError(String s)
+    {
+        errorMsg.error(0, 0, s);
+    }
+
+    /**
+     *
+     */
+    public void reportError(int line, int column, String s)
+    {
+        errorMsg.error(line, column, s);
+    }
+
+    /**
+     * ANTLR method called when a warning was detected.
+     */
+    public void reportWarning(String s)
+    {
+        throw new JDOQueryException(s);
+    }
+
+}
+
+// ----------------------------------
+// rules: import declaration
+// ----------------------------------
+
+parseImports
+{   
+    errorMsg.setContext("declareImports");  //NOI18N
+}
+    :   ( declareImport ( SEMI! declareImport )* )? ( SEMI! )? EOF!
+    ;
+
+declareImport
+    :   i:IMPORT^ q:qualifiedNameStar
+        {
+            if (#q.getType() == STAR) {
+                #i.setType(IMPORT_ON_DEMAND);
+                #i.setFirstChild(#q.getFirstChild());
+            }
+        }
+    ;
+
+// ----------------------------------
+// rules: parameter declaration
+// ----------------------------------
+
+parseParameters
+{   
+    errorMsg.setContext("declareParameters"); //NOI18N
+}
+    :   ( declareParameter ( COMMA! declareParameter )* )? ( COMMA! )? EOF!
+    ;
+
+declareParameter
+    :   type IDENT
+        { 
+            ParameterDecl paramDecl = 
+                new ParameterDecl(new Token(PARAMETER_DECL,"parameterDecl")); //NOI18N
+            paramDecl.setFirstChild(#declareParameter);
+            #declareParameter = paramDecl;
+    }
+    ;
+
+// ----------------------------------
+// rules: variables declaration
+// ----------------------------------
+
+parseVariables
+{   
+    errorMsg.setContext("declareVariables");  //NOI18N
+}
+    :   ( declareVariable ( SEMI! declareVariable )* )? ( SEMI! )? EOF!
+    ;
+
+declareVariable
+    :   type IDENT
+        {  
+            VariableDecl variableDecl = 
+                new VariableDecl(new Token(VARIABLE_DECL,"variableDecl")); //NOI18N
+            variableDecl.setFirstChild(#declareVariable);
+            #declareVariable = variableDecl;
+        }
+    ;
+
+// ----------------------------------
+// rules ordering specification
+// ----------------------------------
+
+parseOrdering
+{   
+    errorMsg.setContext("setOrdering");  //NOI18N
+}
+    :   ( orderSpec ( COMMA! orderSpec )* )? ( COMMA! )? EOF!
+    ;
+
+orderSpec
+    :   e:expression ( ASCENDING^ | DESCENDING^ )
+    ; 
+
+// ----------------------------------
+// rules filer expression
+// ----------------------------------
+
+parseFilter
+{  
+    errorMsg.setContext("setFilter");  //NOI18N
+}
+    :   e:expression EOF!
+    ;
+
+// This is a list of expressions.
+expressionList
+    :   expression (COMMA! expression)*
+    ;
+
+expression
+    :   invalidExpression
+    ;
+
+// assignment expression: not supported => syntax error
+invalidExpression
+    :   conditionalOrExpression 
+        ( 
+            op:invalidOperator
+            {
+                errorMsg.error(#op.getLine(), #op.getColumn(), 
+                    msg.msg("EXC_UnexpectedToken", #op.getText())); //NOI18N
+            }
+            invalidExpression
+        )?
+    ;
+
+invalidOperator
+    :   ASSIGN | PLUS_ASSIGN | MINUS_ASSIGN | STAR_ASSIGN | 
+        DIV_ASSIGN | BAND_ASSIGN | BOR_ASSIGN | SR | SL
+    ;
+
+// conditional or ||
+conditionalOrExpression
+    :   conditionalAndExpression (OR^ conditionalAndExpression)*
+    ;
+
+// conditional and &&
+conditionalAndExpression
+    :   inclusiveOrExpression (AND^ inclusiveOrExpression)*
+    ;
+
+// bitwise or logical or |
+inclusiveOrExpression
+    :   andExpression (BOR^ andExpression)*
+    ;
+
+// bitwise or logical and &
+andExpression
+    :   equalityExpression (BAND^ equalityExpression)*
+    ;
+
+// equality/inequality ==/!=
+equalityExpression
+    :   relationalExpression ((NOT_EQUAL^ | EQUAL^) relationalExpression)*
+    ;
+// boolean relational expressions
+relationalExpression
+    :   additiveExpression
+        (   (   LT^
+            |   GT^
+            |   LE^
+            |   GE^
+            )
+            additiveExpression
+        )*
+    ;
+
+// binary addition/subtraction
+additiveExpression
+    :   multiplicativeExpression ((PLUS^ | MINUS^) multiplicativeExpression)*
+    ;
+// multiplication/division/modulo
+multiplicativeExpression
+    :   unaryExpression ((STAR^ | DIV^ ) unaryExpression)*
+    ;
+
+unaryExpression
+    :   MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression
+    |   PLUS^  {#PLUS.setType(UNARY_PLUS);} unaryExpression
+    |   i:INC^ unaryExpression
+        {
+            errorMsg.error(#i.getLine(), #i.getColumn(), 
+                msg.msg("EXC_UnexpectedToken", #i.getText())); //NOI18N
+        }
+    |   d:DEC^ unaryExpression
+        {
+            errorMsg.error(#d.getLine(), #d.getColumn(), 
+                msg.msg("EXC_UnexpectedToken", #d.getText())); //NOI18N
+        }
+    |   unaryExpressionNotPlusMinus
+    ;
+
+unaryExpressionNotPlusMinus
+    :   BNOT^ unaryExpression
+    |   LNOT^ unaryExpression
+    |   ( LPAREN type RPAREN unaryExpression )=>
+          lp:LPAREN^ {#lp.setType(CAST);} type RPAREN! unaryExpression
+    |   postfixExpression
+    ;
+
+// qualified names, field access, method invocation
+postfixExpression
+    :   primary
+        (   DOT^ IDENT ( argList )? )*
+    ;
+
+argList
+    :   LPAREN!
+        (   expressionList
+            {
+                NodeImpl argListRoot = new NodeImpl(new Token(ARG_LIST,"argList")); //NOI18N
+                argListRoot.setFirstChild(#argList);
+                #argList = argListRoot;
+            }
+        |   /* empty list */
+            {
+                NodeImpl argListRoot = new NodeImpl(new Token(ARG_LIST,"argList")); //NOI18N
+                #argList = argListRoot;
+            }
+        )
+        RPAREN!
+    ;
+
+// the basic element of an expression
+primary
+    :   IDENT
+    |   literal
+    |   THIS
+    |   LPAREN! expression RPAREN!
+    ;
+
+literal
+    :   TRUE
+    |   FALSE
+    |   INT_LITERAL
+    |   LONG_LITERAL
+    |   FLOAT_LITERAL
+    |   DOUBLE_LITERAL
+    |   c:CHAR_LITERAL
+        {
+            // strip quotes from the token text
+            String text = #c.getText();
+            #c.setText(text.substring(1,text.length()-1));
+        }
+    |   s:STRING_LITERAL
+        {
+            // strip quotes from the token text
+            String text = #s.getText();
+            #s.setText(text.substring(1,text.length()-1));
+        }
+    |   NULL
+    ;
+
+qualifiedName
+    :   IDENT ( DOT^ IDENT )*
+    ;
+
+qualifiedNameStar
+    :   IDENT ( DOT^ IDENT )* ( DOT! STAR^ )?
+    ;
+
+type
+    :   qualifiedName
+    |   primitiveType
+    ;
+
+// The primitive types.
+primitiveType
+    :   BOOLEAN
+    |   BYTE
+    |   CHAR
+    |   SHORT
+    |   INT
+    |   FLOAT
+    |   LONG
+    |   DOUBLE
+    ;

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLAST.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLAST.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLAST.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLAST.java Sun May 22 11:08:57 2005
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * JDOQLAST.java
+ *
+ * Created on August 28, 2001
+ */
+
+package org.apache.jdo.impl.jdoql.jdoqlc;
+
+import org.apache.jdo.model.java.JavaType;
+
+import antlr.Token;
+import antlr.CommonAST;
+import antlr.collections.AST;
+
+
+/** 
+ * This class represents a node in the intermediate representation (AST) 
+ * used by the query compiler. 
+ * It provides
+ * - line info
+ * - column info
+ * - type info (JavaType instance): the semantic analysis calculates 
+ *   the type of an expression and adds this info to each node.
+ * @author  Michael Bouschen
+ */
+public class JDOQLAST
+    extends CommonAST
+    implements Cloneable
+{
+    /** The line info */
+    protected int line = 0;
+
+    /** The column info */
+    protected int column = 0;
+
+    /** The type info */
+    protected transient JavaType typeInfo;
+
+    /** */
+    public JDOQLAST()
+    {
+    }
+
+    /** */
+    public JDOQLAST(int type, String text, JavaType typeInfo)
+    {
+        initialize(type, text, typeInfo);
+    }
+
+    /** */
+    public JDOQLAST(JDOQLAST ast)
+    {
+        initialize(ast);
+    }
+    
+    /** */
+    public void initialize(Token t)
+    {
+        setType(t.getType());
+        setText(t.getText());
+        setLine(t.getLine());
+        setColumn(t.getColumn());
+    }
+
+    /** */
+    public void initialize(int type, String text, JavaType typeInfo)
+    {
+        setType(type);
+        setText(text);
+        setTypeInfo(typeInfo);
+    }
+
+    /** */
+    public void initialize(AST _ast)
+    {
+        JDOQLAST ast = (JDOQLAST)_ast;
+        setType(ast.getType());
+        setText(ast.getText());
+        setLine(ast.getLine());
+        setColumn(ast.getColumn());
+        setTypeInfo(ast.getTypeInfo());
+    }
+    
+    /** */
+    public void setLine(int line)
+    {
+        this.line = line;
+    }
+
+    /** */
+    public int getLine()
+    {
+        return line;
+    }
+
+    /** */
+    public void setColumn(int column)
+    {
+        this.column = column;
+    }
+
+    /** */
+    public int getColumn()
+    {
+        return column;
+    }
+
+    /** */
+    public void setTypeInfo(JavaType typeInfo)
+    {
+        this.typeInfo = typeInfo;
+    }
+
+    /** */
+    public JavaType getTypeInfo()
+    {
+        return typeInfo;
+    }
+
+    /** 
+     * Returns a string representation of this JDOQLAST.
+     * @return a string representation of the object.
+     */
+    public String toString()
+    {
+        JavaType typeInfo = getTypeInfo();
+        StringBuffer repr = new StringBuffer();
+        // token text
+        repr.append((getText() == null ? "null" : getText())); //NOI18N
+        repr.append(" ["); //NOI18N
+        // token type
+        repr.append(getType());
+        // line/column info
+        repr.append(", ("); //NOI18N
+        repr.append(getLine() + "/" + getColumn()); //NOI18N
+        repr.append("), "); //NOI18N
+        // type info
+        repr.append(typeInfo);
+        repr.append(", "); //NOI18N
+        // node class info
+        String className = getClass().getName();
+        int index = className.lastIndexOf('.');
+        if (index > -1)
+            className = className.substring(index+1);
+        repr.append(className);
+        repr.append("]"); //NOI18N
+        return repr.toString();
+    }
+
+    /**
+     * Returns a string representation of this JDOQLAST including 
+     * all child nodes.
+     * @return a string representation of this JDOQLAST including all
+     * child nodes.
+     */
+    public String treeToString() 
+    {
+        StringBuffer repr = new StringBuffer();
+        treeToString(0, repr);
+        return repr.toString();
+    }
+
+    /**
+     * Creates and returns a copy of this object.
+     * The returned JDOQLAST shares the same state as this object, meaning 
+     * the fields type, text, line, column, and typeInfo have the same values. 
+     * But it is not bound to any tree structure, thus the child is null 
+     * and the sibling is null.
+     * @return a clone of this instance.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException
+    {
+        JDOQLAST clone = (JDOQLAST)super.clone();
+        clone.setFirstChild(null);
+        clone.setNextSibling(null);
+        return clone;
+    }
+    
+    // Internal helper method
+
+    /** */
+    private void treeToString(int indent, StringBuffer repr) 
+    {
+        // indent
+        for (int i = 0; i < indent; i++) {
+            repr.append("   "); //NOI18N
+        }
+
+        // append string representation of current node
+        repr.append(toString());
+
+        // child nodes in new line
+        repr.append("\n");
+
+        // append string representation(s) of child nodes
+        for (JDOQLAST node = (JDOQLAST)this.getFirstChild(); 
+             node != null; 
+             node = (JDOQLAST)node.getNextSibling()) {
+            node.treeToString(indent+1, repr);
+        }
+    }
+}
+

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLASTFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLASTFactory.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLASTFactory.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLASTFactory.java Sun May 22 11:08:57 2005
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * JDOQLASTFactory.java
+ *
+ * Created on September 3, 2001
+ */
+
+package org.apache.jdo.impl.jdoql.jdoqlc;
+
+import antlr.collections.AST;
+import antlr.ASTFactory;
+
+import javax.jdo.JDOFatalInternalException;
+
+import org.apache.jdo.util.I18NHelper;
+
+/** 
+ * Factory to create and connect JDOQLAST nodes.
+ *
+ * @author  Michael Bouschen
+ */
+public class JDOQLASTFactory
+    extends ASTFactory
+{
+    /** The singleton JDOQLASTFactory instance. */    
+    private static JDOQLASTFactory factory = new JDOQLASTFactory();
+
+    /** I18N support. */
+    private final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", JDOQLASTFactory.class.getClassLoader()); //NOI18N
+    
+    /** 
+     * Get an instance of JDOQLASTFactory.
+     * @return an instance of JDOQLASTFactory
+     */    
+    public static JDOQLASTFactory getInstance()
+    {
+        return factory;
+    }
+    
+    /**
+     *
+     */
+    protected JDOQLASTFactory()
+    {
+        this.theASTNodeTypeClass = JDOQLAST.class;
+        this.theASTNodeType = this.theASTNodeTypeClass.getName();
+    }
+    
+    /**
+     *
+     */
+    public AST create() 
+    {
+        return new JDOQLAST();
+    }
+
+    /**
+     *
+     */
+    public AST create(AST tr) 
+    { 
+        return create((JDOQLAST)tr);
+    }
+
+    /**
+     *
+     */
+    public JDOQLAST create(JDOQLAST tr) 
+    { 
+        try {
+            return (tr==null) ? null : (JDOQLAST)tr.clone();
+        }
+        catch(CloneNotSupportedException ex) {
+            throw new JDOFatalInternalException(
+                msg.msg("ERR_UnexpectedExceptionClone"), ex); //NOI18N
+        }
+    }
+}
+

Added: incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLC.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLC.java?rev=171353&view=auto
==============================================================================
--- incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLC.java (added)
+++ incubator/jdo/trunk/query20/src/java/org/apache/jdo/impl/jdoql/jdoqlc/JDOQLC.java Sun May 22 11:08:57 2005
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+/*
+ * JDOQLC.java
+ *
+ * Created on August 28, 2001
+ */
+
+package org.apache.jdo.impl.jdoql.jdoqlc;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Collection;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.impl.jdoql.scope.ParameterTable;
+import org.apache.jdo.impl.jdoql.scope.VariableTable;
+import org.apache.jdo.impl.jdoql.tree.Tree;
+import org.apache.jdo.jdoql.JDOQueryException;
+import org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+import antlr.TokenBuffer;
+import antlr.ANTLRException;
+
+/** 
+ * This class controls the JDOQL compiler passes.
+ *
+ * @author  Michael Bouschen
+ */
+public class JDOQLC
+{
+    /** The persistence manager of the query instance. */
+    protected PersistenceManagerInternal pm;
+
+    /** Type support. */
+    protected TypeSupport typeSupport;
+
+    /** Error message helper. */
+    protected ErrorMsg errorMsg;    
+    
+    /** The candidate class. */
+    protected Class candidateClass;
+    
+    /** The AST representing the filter expression. */
+    protected JDOQLAST filterAST = null;
+    
+    /** The AST representing the import declarations. */
+    protected JDOQLAST importsAST = null;
+    
+    /** The AST representing the parameter declarations. */
+    protected JDOQLAST paramsAST = null;
+    
+    /** The AST representing the variable declarations. */
+    protected JDOQLAST varsAST = null;
+    
+    /** The AST representing the ordering specification. */
+    protected JDOQLAST orderingAST = null;
+
+    /** The complete query tree. */
+    protected JDOQLAST queryTree = null;
+    
+    /** I18N support */
+    private final static I18NHelper msg = I18NHelper.getInstance(
+        "org.apache.jdo.impl.jdoql.Bundle", //NOI18N
+        JDOQLC.class.getClassLoader());
+
+    /** Logger */
+    private static Log logger = LogFactory.getFactory().getInstance(
+        "org.apache.jdo.impl.jdoql.jdoqlc"); //NOI18N
+    
+    /**
+     *
+     */
+    public JDOQLC(PersistenceManagerInternal pm)
+    {
+        this.pm = pm;
+        this.typeSupport = new TypeSupport();
+        this.errorMsg = new ErrorMsg();
+    }
+    
+    /**
+     *
+     */
+    public void setClass(Class candidateClass)
+    {
+        // Method semanticCheck checks for valid candidateClass
+        this.candidateClass = candidateClass;
+    }
+
+    /**
+     *
+     */
+    public void declareImports(String imports)
+    {
+        if (imports == null) {
+            importsAST = null;
+            return;
+        }
+
+        try {
+            JDOQLParser parser = createStringParser(imports);
+            parser.parseImports();
+            importsAST = (JDOQLAST)parser.getAST();        
+        }
+        catch (ANTLRException ex) {
+            JDOQLLexer.handleANTLRException(ex, errorMsg);
+        }
+    }
+    
+    /**
+     *
+     */
+    public void declareParameters(String parameters)
+    {
+        if (parameters == null) { 
+            paramsAST = null;
+            return;
+        }
+        
+        try {
+            JDOQLParser parser = createStringParser(parameters);
+            parser.parseParameters();
+            paramsAST = (JDOQLAST)parser.getAST();        
+        }
+        catch (ANTLRException ex) {
+            JDOQLLexer.handleANTLRException(ex, errorMsg);
+        }
+    }
+    
+    /**
+     *
+     */
+    public void declareVariables(String variables)
+    {
+        if (variables == null) {
+            varsAST = null;
+            return;
+        }
+        
+        try {
+            JDOQLParser parser = createStringParser(variables);
+            parser.parseVariables();
+            varsAST = (JDOQLAST)parser.getAST();        
+        }
+        catch (ANTLRException ex) {
+            JDOQLLexer.handleANTLRException(ex, errorMsg);
+        }
+    }
+    
+    /**
+     *
+     */
+    public void setOrdering(String ordering)
+    {
+        if (ordering == null) {
+            orderingAST = null;
+            return;
+        }
+        
+        try {
+            JDOQLParser parser = createStringParser(ordering);
+            parser.parseOrdering();
+            orderingAST = (JDOQLAST)parser.getAST();        
+        }
+        catch (ANTLRException ex) {
+            JDOQLLexer.handleANTLRException(ex, errorMsg);
+        }
+    }
+    
+    /**
+     *
+     */
+    public void setFilter(String filter)
+    {
+        if ((filter == null) || (filter.trim().length() == 0)) {
+            // If there is no filter specified use "true" as filter.
+            // This is the case if 
+            // - setFilter is not called at all (filter == null)
+            // - the filter is empty or contians whitespecace only.
+            // Internally the filter has to be specified, 
+            // otherwise semantic analysis has problems with empty AST.
+            filter = "true"; //NOI18N
+        }
+        
+        try {
+            JDOQLParser parser = createStringParser(filter);
+            parser.parseFilter();
+            filterAST = (JDOQLAST)parser.getAST();        
+        }
+        catch (ANTLRException ex) {
+            JDOQLLexer.handleANTLRException(ex, errorMsg);
+        }
+     }
+
+    /**
+     *
+     */
+    public void setQueryTree(JDOQLAST queryTree)
+    {
+        this.queryTree = queryTree;
+    }
+
+    /**
+     *
+     */
+    public JDOQLAST semanticCheck(ParameterTable paramtab, VariableTable vartab)
+    {
+        boolean trace = logger.isTraceEnabled();
+        ClassLoader applClassLoader = null;
+
+        Semantic semantic = new Semantic();
+        semantic.init(typeSupport, paramtab, vartab, errorMsg);
+        semantic.setASTFactory(JDOQLASTFactory.getInstance());
+
+        if (queryTree == null) {
+            // check candidate class
+            if (candidateClass == null) {
+                throw new JDOQueryException(
+                    msg.msg("EXC_MissingCandidateClass")); //NOI18N
+            }
+            applClassLoader = candidateClass.getClassLoader();
+            // create complete tree representation
+            queryTree = semantic.createQueryTree(
+                candidateClass, importsAST, paramsAST, 
+                varsAST, orderingAST, filterAST);
+        }
+        else {
+            Tree tree = (Tree)queryTree;
+            Class clazz = tree.getCandidateClass();
+            if (clazz != null)
+                applClassLoader = clazz.getClassLoader();
+            tree.initANTLRAST();
+        }
+
+        // set the candidateClass class loader
+        typeSupport.initApplicationJavaModel(applClassLoader);
+
+        if (trace)
+            logger.trace("AST\n" + queryTree.treeToString()); //NOI18N
+
+        try {
+            if (logger.isDebugEnabled())
+                logger.debug("Start semantic analysis"); //NOI18N
+            semantic.query(queryTree);
+            queryTree = (JDOQLAST)semantic.getAST();
+            if (trace)
+                logger.trace("Typed AST\n" + queryTree.treeToString()); //NOI18N
+        }
+        catch (ANTLRException ex) {
+            ex.printStackTrace();
+            errorMsg.fatal(
+                msg.msg("ERR_UnexpectedExceptionSemantic"), ex); //NOI18N
+        }
+        return queryTree;
+    }
+
+    /**
+     *
+     */
+    public JDOQLAST optimize(JDOQLAST tree)
+    {
+        // Do not include parameters into optimization => paramtab == null
+        return optimize(tree, null);
+    }
+
+    /**
+     *
+     */
+    public JDOQLAST optimize(JDOQLAST tree, ParameterTable paramtab)
+    {
+        Tree ast = null;
+        Optimizer optimizer= new Optimizer();
+        optimizer.init(pm, paramtab, errorMsg);
+        optimizer.setASTFactory(JDOQLASTFactory.getInstance());
+        
+        try {
+            if (logger.isDebugEnabled())
+                logger.debug("START optimizer"); //NOI18N
+            optimizer.query(tree);
+            ast = (Tree)optimizer.getAST();
+            if (logger.isTraceEnabled())
+                logger.trace("Optimized AST\n" + queryTree.treeToString()); //NOI18N
+        }
+        catch (ANTLRException ex) {
+            ex.printStackTrace();
+            errorMsg.fatal(
+                msg.msg("ERR_UnexpectedExceptionOptimizer"), ex); //NOI18N
+        }
+        return ast;
+    }
+
+    //========= Internal helper methods ==========
+    
+    /**
+     *
+     */
+    private JDOQLParser createStringParser(String text)
+    {
+        Reader in = new StringReader(text);
+        JDOQLLexer lexer = new JDOQLLexer(in);
+        lexer.init(errorMsg);
+        TokenBuffer buffer = new TokenBuffer(lexer);
+        JDOQLParser parser = new JDOQLParser(buffer);
+        parser.init(errorMsg);
+        parser.setASTFactory(JDOQLASTFactory.getInstance());
+        return parser;
+    }
+    
+}