Index: test/java/org/apache/jdo/tck/query/QueryTest.java =================================================================== --- test/java/org/apache/jdo/tck/query/QueryTest.java (Revision 294784) +++ test/java/org/apache/jdo/tck/query/QueryTest.java (Arbeitskopie) @@ -19,14 +19,16 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; -import java.util.Map; import javax.jdo.Extent; import javax.jdo.JDOFatalInternalException; +import javax.jdo.JDOUserException; import javax.jdo.PersistenceManager; import javax.jdo.Query; import javax.jdo.Transaction; @@ -381,4 +383,277 @@ logger.debug("X = " + pcp.getX() + "\tY = " + pcp.getY()); } } + + // company model helper methods + + /** + * Returns an array of company mode instances for beans names + * in the given argument. + * @param beanNames the bean names of company mode instances. + * @return the array of company model instances. + */ + protected Object[] getCompanyModelInstances(String[] beanNames) { + CompanyModelReader reader = new CompanyModelReader(COMPANY_TESTDATA); + Object[] result = new Object[beanNames.length]; + for (int i = 0; i < beanNames.length; i++) { + result[i] = reader.getBean(beanNames[i]); + } + return result; + } + + // compile query methods + + /** + * Compiles the given query element holder instance as a JDO API query. + * Argument positive determines if the compilation is supposed + * to succeed or to fail. If true and the compilation fails, + * then the test case fails prompting argument assertion. + * If false and the compilation succeeds, + * then the test case fails prompting argument assertion. + * Otherwise the test case succeeds. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param positive determines if the compilation is supposed + * to succeed or to fail. + */ + protected void compileAPIQuery(String assertion, + QueryElementHolder queryElementHolder, boolean positive) { + if (logger.isDebugEnabled()) { + logger.debug("Compiling API query: " + queryElementHolder); + } + compile(assertion, queryElementHolder, + queryElementHolder.toString(), positive); + } + + /** + * Compiles the given query element holder instance + * as a JDO single string query. + * Argument positive determines if the compilation is supposed + * to succeed or to fail. If true and the compilation fails, + * then the test case fails prompting argument assertion. + * If false and the compilation succeeds, + * then the test case fails prompting argument assertion. + * Otherwise the test case succeeds. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param positive determines if the compilation is supposed + * to succeed or to fail. + */ + protected void compileSingleStringQuery(String assertion, + QueryElementHolder queryElementHolder, boolean positive) { + compileSingleStringQuery(assertion, + queryElementHolder.toString(), positive); + } + + /** + * Compiles the given single string query. + * Argument positive determines if the compilation is supposed + * to succeed or to fail. If true and the compilation fails, + * then the test case fails prompting argument assertion. + * If false and the compilation succeeds, + * then the test case fails prompting argument assertion. + * Otherwise the test case succeeds. + * @param assertion the assertion to prompt if the test case fails. + * @param singleStringQuery the single string query + * @param positive determines if the compilation is supposed + * to succeed or to fail. + */ + protected void compileSingleStringQuery(String assertion, + String singleStringQuery, boolean positive) { + if (logger.isDebugEnabled()) + logger.debug("Compiling single string query: " + + singleStringQuery); + compile(assertion, null, singleStringQuery, positive); + } + + /** + * Compiles the given query element holder instance + * as a JDO API query or single string query, + * depending if argument queryElementHolder + * is null. + * Argument positive determines if the compilation is supposed + * to succeed or to fail. If true and the compilation fails, + * then the test case fails prompting argument assertion. + * If false and the compilation succeeds, + * then the test case fails prompting argument assertion. + * Otherwise the test case succeeds. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute as a JDO API query. + * @param singleStringQuery the query to execute + * as a JDO single string query. + * @param positive determines if the compilation is supposed + * to succeed or to fail. + */ + private void compile(String assertion, + QueryElementHolder queryElementHolder, + String singleStringQuery, boolean positive) { + PersistenceManager pm = getPM(); + Transaction tx = pm.currentTransaction(); + tx.begin(); + try { + Query query; + if (queryElementHolder != null) { + query = queryElementHolder.getAPIQuery(pm); + } else { + query = getPM().newQuery(singleStringQuery); + } + query.compile(); + if (!positive) { + fail(assertion + + "Query compilation must throw JDOUserException: " + + singleStringQuery); + } + } catch (JDOUserException e) { + if (positive) { + fail(assertion + "Query '" + singleStringQuery + + "' must be compilable. The exception message is: " + + e.getMessage()); + } + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + // execute query methods + + /** + * Executes the given query element holder instance as a JDO API query. + * The result of that query is compared against the given argument + * expectedResult. The array elements of that argument + * must match the content of the result collection + * returned by {@link Query#execute()}. + * If the expected result does not match the returned query result, + * then the test case fails prompting argument assertion. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param expectedResult the expected query result. + */ + protected void executeAPIQuery(String assertion, + QueryElementHolder queryElementHolder, Object[] expectedResult) { + executeAPIQuery(assertion, queryElementHolder, null, expectedResult); + } + + /** + * Executes the given query element holder instance as a JDO API query. + * The result of that query is compared against the given argument + * expectedResult. The array elements of that argument + * must match the content of the result collection + * returned by {@link Query#executeWithArray(java.lang.Object[])}. + * Argument parameters is passed as the parameter + * to that method. + * If the expected result does not match the returned query result, + * then the test case fails prompting argument assertion. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param parameters the parmaters of the query. + * @param expectedResult the expected query result. + */ + protected void executeAPIQuery(String assertion, + QueryElementHolder queryElementHolder, + Object[] parameters, Object[] expectedResult) { + if (logger.isDebugEnabled()) { + logger.debug("Executing API query: " + queryElementHolder); + } + execute(assertion, queryElementHolder, false, + parameters, expectedResult); + } + + /** + * Executes the given query element holder instance + * as a JDO single string query. + * The result of that query is compared against the given argument + * expectedResult. The array elements of that argument + * must match the content of the result collection + * returned by {@link Query#execute()}. + * If the expected result does not match the returned query result, + * then the test case fails prompting argument assertion. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param expectedResult the expected query result. + */ + protected void executeSingleStringQuery(String assertion, + QueryElementHolder queryElementHolder, Object[] expectedResult) { + executeSingleStringQuery(assertion, queryElementHolder, + null, expectedResult); + } + + /** + * Executes the given query element holder instance + * as a JDO single string query. + * The result of that query is compared against the given argument + * expectedResult. The array elements of that argument + * must match the content of the result collection + * returned by {@link Query#executeWithArray(java.lang.Object[])}. + * Argument parameters is passed as the parameter + * to that method. + * If the expected result does not match the returned query result, + * then the test case fails prompting argument assertion. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param parameters the parmaters of the query. + * @param expectedResult the expected query result. + */ + protected void executeSingleStringQuery(String assertion, + QueryElementHolder queryElementHolder, + Object[] parameters, Object[] expectedResult) { + if (logger.isDebugEnabled()) + logger.debug("Executing single string query: " + + queryElementHolder); + execute(assertion, queryElementHolder, true, + parameters, expectedResult); + } + + /** + * Executes the given query element holder instance + * as a JDO API query of a single string query, + * depending on argument asSingleString. + * The result of that query is compared against the given argument + * expectedResult. The array elements of that argument + * must match the content of the result collection + * returned by {@link Query#executeWithArray(java.lang.Object[])}. + * Argument parameters is passed as the parameter + * to that method. + * If the expected result does not match the returned query result, + * then the test case fails prompting argument assertion. + * @param assertion the assertion to prompt if the test case fails. + * @param queryElementHolder the query to execute. + * @param asSingleString determines if the query is executed as + * singole string query or as API query. + * @param parameters the parmaters of the query. + * @param expectedResult the expected query result. + * @return + */ + private Object execute(String assertion, + QueryElementHolder queryElementHolder, boolean asSingleString, + Object[] parameters, Object[] expectedResult) { + Object result; + PersistenceManager pm = getPM(); + Transaction tx = pm.currentTransaction(); + tx.begin(); + try { + Query query = asSingleString ? + queryElementHolder.getSingleStringQuery(pm) : + queryElementHolder.getAPIQuery(pm); + result = parameters != null ? + query.executeWithArray(parameters) : query.execute(); + + if (queryElementHolder.isUnique()) { + Collection resultCollection = new LinkedList(); + resultCollection.add(result); + result = resultCollection; + } + + Collection expectedResultCollection = + Arrays.asList(expectedResult); + checkQueryResultWithoutOrder(assertion, result, + expectedResultCollection); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + return result; + } } Index: test/java/org/apache/jdo/tck/query/QueryElementHolder.java =================================================================== --- test/java/org/apache/jdo/tck/query/QueryElementHolder.java (Revision 0) +++ test/java/org/apache/jdo/tck/query/QueryElementHolder.java (Revision 0) @@ -0,0 +1,252 @@ +/* + * 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. + */ + +package org.apache.jdo.tck.query; + +import javax.jdo.Extent; +import javax.jdo.PersistenceManager; +import javax.jdo.Query; + +/** + * This class is an abstraction of a JDOQL query, + * which may be represented as a single string + * (e.g. SELECT FROM Person WHERE personid == 1) or + * as an API query using methods on class {@link Query}.

+ * + * The class may be used as the factory of a JDO {@link Query} instance + * using method {@link QueryElementHolder#getAPIQuery(PersistenceManager)} or + * method {@link QueryElementHolder#getSingleStringQuery(PersistenceManager).

+ * + * Instances of this class are capable to hold all elements of a JDOQL query, + * e.g. the candidate class, the filter, etc. These elements are passed + * calling the constructor. It is valid to pass null as a value + * for JDOQL querys elements. Such elements are not transfered into a + * JDO {@link Query} instance. + * Instead, the default of JDO {@link Query} instance is taken. + */ +public class QueryElementHolder { + + // fields holding JDOQL query elements + private Boolean unique; + private String result; + private Class resultClass; + private Class candidateClass; + private Boolean excludeSubClasses; + private String filter; + private String variables; + private String parameters; + private String imports; + private String grouping; + private String ordering; + private Long from; + private Long to; + + /** + * Returns an instance of this class holding the given arguments + * such as the candidate class, the filter, etc. + * The given arguments represent JDOQL query elements. + * It is valid to pass null as a value + * for JDOQL querys elements. Such elements are not transfered into a + * JDO {@link Query} instance. + * Instead, the default of JDO {@link Query} instance is taken. + * @param unique the JDOQL unique query element + * @param result the JDOQL result query element + * @param resultClass the JDOQL result class query element + * @param candidateClass the JDOQL candidate class query element + * @param excludeSubClasses the JDOQL exclude subclasses query element + * @param filter the JDOQL filter query element + * @param variables the JDOQL variables query element + * @param parameters the JDOQL parameters query element + * @param imports the JDOQL imports query element + * @param grouping the JDOQL grouping query element + * @param ordering the JDOQL ordering query element + * @param from the JDOQL range from query element + * @param to the JDOQL range to query element + */ + public QueryElementHolder(Boolean unique, String result, + Class resultClass, Class candidateClass, + Boolean excludeSubClasses, String filter, + String variables, String parameters, String imports, + String grouping, String ordering, Long from, Long to) { + this.unique = unique; + this.result = result; + this.resultClass = resultClass; + this.candidateClass = candidateClass; + this.excludeSubClasses = excludeSubClasses; + this.filter = filter; + this.variables = variables; + this.parameters = parameters; + this.imports = imports; + this.grouping = grouping; + this.ordering = ordering; + this.from = from; + this.to = to; + } + + /** + * @see Object#toString() + */ + public String toString() { + return "SELECT " + + toString("UNIQUE", this.unique) + + toString(this.result) + + toString("INTO", this.resultClass) + + toString("FROM", this.candidateClass) + + toString("EXCLUDE SUBCLASSES", this.excludeSubClasses) + + toString("WHERE", this.filter) + + toString("VARIABLES", this.variables) + + toString("PARAMETERS", this.parameters) + + toString("IMPORTS", this.imports) + + toString("GROUP BY", this.grouping) + + toString("ORDER BY", this.ordering) + + rangeToString(); + } + + /** + * Creates a JDO {@link Query} instance using the JDOQL query elements + * of this instance. The returned instance is created calling + * {@link PersistenceManager#newQuery(String)}. + * The passed {@link String} instance is the + * single string representation of this, + * e.g. SELECT FROM Person WHERE personid == 1. + * @param pm the persistence manager + * @return the JDO query instance + */ + public Query getSingleStringQuery(PersistenceManager pm) { + return pm.newQuery(toString()); + } + + /** + * Creates a JDO {@link Query} instance using the JDOQL query elements + * of this instance. The returned instance is created calling + * {@link PersistenceManager#newQuery(Extent)}. + * Afterwards, all query elements of this are transfered + * into that instance. + * @param pm the persistence manager + * @return the JDO query instance + */ + public Query getAPIQuery(PersistenceManager pm) { + Query query = this.excludeSubClasses != null ? + pm.newQuery(pm.getExtent(this.candidateClass, + !this.excludeSubClasses.booleanValue())) : + pm.newQuery(pm.getExtent(this.candidateClass)); + if (this.unique != null) { + query.setUnique(this.unique.booleanValue()); + } + if (this.result != null ) { + query.setResult(this.result); + } + if (this.resultClass != null) { + query.setResultClass(this.resultClass); + } + if (this.filter != null) { + query.setFilter(this.filter); + } + if (this.variables != null) { + query.declareVariables(this.variables); + } + if (this.parameters != null) { + query.declareParameters(this.parameters); + } + if (this.imports != null ) { + query.declareImports(this.imports); + } + if (this.grouping != null) { + query.setGrouping(this.grouping); + } + if (this.ordering != null) { + query.setOrdering(this.ordering); + } + if (this.from != null && this.to != null && + this.from.longValue() >= 0 && this.to.longValue() >= 0) { + query.setRange(this.from.longValue(), this.to.longValue()); + } + return query; + } + + /** + * Returns the unique JDOQL query element. + * @return the unique JDOQL query element. + */ + protected boolean isUnique() { + return this.unique != null && this.unique.booleanValue(); + } + + /** + * Delegates to {@link QueryElementHolder#toString(String, String) + * if argument clazz does not equal null, + * otherwise returns an empty string. + * @param prefix the prefix of the returned string. + * @param clazz the returned string has the class name as a suffix. + * @return the string. + */ + private String toString(String prefix, Class clazz) { + return (clazz != null? toString(prefix, clazz.getName()) : ""); + } + + /** + * Returns a string prefixed by argument prefix and + * suffixed by the string representation of argument bool, + * if argument bool does not equal null. + * Otherwise, an empty string is returned. + * @param prefix the prefix of the returned string. + * @param bool the returned string has the string representation + * of the value as a suffix. + * @return the string. + */ + private String toString(String prefix, Boolean bool) { + return bool!=null && bool.booleanValue() ? prefix + ' ' : ""; + } + + /** + * Returns a string prefixed by argument prefix and + * suffixed by argument suffix, + * if argument suffix does not equal null. + * Otherwise, an empty string is returned. + * @param prefix the prefix of the returned string. + * @param suffix the suffix of the returned string. + * @return the string. + */ + private String toString(String prefix, String suffix) { + return (suffix != null ? prefix + ' ' + suffix + ' ' : ""); + } + + /** + * Returns a string prefixed by argument prefix, + * if argument prefix does not equal null. + * Otherwise, an empty string is returned. + * @param prefix the prefix of the returned string. + * @return the string. + */ + private String toString(String prefix) { + return (prefix != null ? prefix + ' ' : ""); + } + + /** + * Returns the single string representation + * of the JDOQL query element range. + * If that element is null, + * then an empty string is returned. + * @return the single string representation + * of the JDOQL query element range or null, + */ + private String rangeToString() { + return (this.from != null && this.to != null && + this.from.longValue() >= 0 && this.to.longValue() >= 0 ? + "RANGE " + this.from + " TO " + this.to: ""); + } + +}