All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.test.api.query.AbstractQueryTest Maven / Gradle / Ivy

There is a newer version: 2.23.1-beta
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.jackrabbit.test.api.query;

import org.apache.jackrabbit.test.AbstractJCRTest;
import org.apache.jackrabbit.test.NotExecutableException;
import org.apache.jackrabbit.test.api.util.ISO9075;

import javax.jcr.query.QueryResult;
import javax.jcr.query.RowIterator;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.qom.QueryObjectModelFactory;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.ValueFactory;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Abstract base class for query test cases.
 */
public abstract class AbstractQueryTest extends AbstractJCRTest {

    /**
     * Resolved Name for jcr:score
     */
    protected String jcrScore;

    /**
     * Resolved Name for jcr:path
     */
    protected String jcrPath;

    /**
     * Resolved Name for jcr:root
     */
    protected String jcrRoot;

    /**
     * Resolved Name for jcr:contains
     */
    protected String jcrContains;

    /**
     * Resolved Name for jcr:deref
     */
    protected String jcrDeref;

    /**
     * The string /${jcrRoot}${testRoot} with all components of the test path
     * properly escaped for XPath.
     *
     * @see JCR-714
     */
    protected String xpathRoot;

    /**
     * The query object model factory for {@link #superuser}.
     */
    protected QueryObjectModelFactory qf;

    /**
     * The value factory for creating literals for the query object model.
     */
    protected ValueFactory vf;

    /**
     * The query manager for {@link #superuser}
     */
    protected QueryManager qm;

    /**
     * The identifier for the "XPATH" query syntax
     */
    @SuppressWarnings("deprecation")
	protected String qsXPATH = Query.XPATH;

    /**
     * The identifier for the "SQL" query syntax
     */
    @SuppressWarnings("deprecation")
	protected String qsSQL = Query.SQL;

    /**
     * Set-up the configuration values used for the test. Per default retrieves
     * a session, configures testRoot, and nodetype and checks if the query
     * language for the current language is available.
*/ protected void setUp() throws Exception { super.setUp(); jcrScore = superuser.getNamespacePrefix(NS_JCR_URI) + ":score"; jcrPath = superuser.getNamespacePrefix(NS_JCR_URI) + ":path"; jcrRoot = superuser.getNamespacePrefix(NS_JCR_URI) + ":root"; jcrContains = superuser.getNamespacePrefix(NS_JCR_URI) + ":contains"; jcrDeref = superuser.getNamespacePrefix(NS_JCR_URI) + ":deref"; xpathRoot = "/" + jcrRoot + ISO9075.encodePath(testRoot); qm = superuser.getWorkspace().getQueryManager(); qf = qm.getQOMFactory(); vf = superuser.getValueFactory(); } protected void tearDown() throws Exception { qm = null; qf = null; vf = null; super.tearDown(); } /** * Create a {@link Query} for a given {@link Statement}. * * @param statement the query should be created for * @return * * @throws RepositoryException * @see #createQuery(String, String) */ protected Query createQuery(Statement statement) throws RepositoryException, NotExecutableException { return createQuery(statement.getStatement(), statement.getLanguage()); } /** * Creates a {@link Query} for the given statement in the requested * language, treating optional languages gracefully * @throws RepositoryException */ protected Query createQuery(String statement, String language) throws RepositoryException, NotExecutableException { return createQuery(superuser, statement, language); } /** * Creates a {@link Query} for the given statement in the requested * language, treating optional languages gracefully * @throws RepositoryException */ protected Query createQuery(Session session, String statement, String language) throws RepositoryException, NotExecutableException { log.println("Creating query: " + statement); // check for unsupported query languages early if (! isSupportedLanguage(language) && !Query.JCR_SQL2.equals(language)) { throw new NotExecutableException("Repository does not support " + language + " query syntax"); } return session.getWorkspace().getQueryManager().createQuery(statement, language); } /** * Creates and executes a {@link Query} for the given {@link Statement} * * @param statement to execute * @return * * @throws RepositoryException * @see #execute(String, String) */ protected QueryResult execute(Statement statement) throws RepositoryException, NotExecutableException { return execute(statement.getStatement(), statement.getLanguage()); } /** * Creates and executes a {@link Query} for a given Statement in a given * query language * * @param statement the query should be build for * @param language query language the stement is written in * @return * * @throws RepositoryException */ protected QueryResult execute(String statement, String language) throws RepositoryException, NotExecutableException { Query query = createQuery(statement, language); return query.execute(); } /** * Checks if the result contains a number of * hits. * * @param result the QueryResult. * @param hits the number of expected hits. * @throws RepositoryException if an error occurs while iterating over the * result nodes. */ protected void checkResult(QueryResult result, int hits) throws RepositoryException { RowIterator itr = result.getRows(); long count = itr.getSize(); if (count == 0) { log.println(" NONE"); } else if (count == -1) { // have to count in a loop count = 0; while (itr.hasNext()) { itr.nextRow(); count++; } } assertEquals("Wrong hit count.", hits, count); } /** * Checks if the result contains a number of hits * and properties. * * @param result the QueryResult. * @param hits the number of expected hits. * @param properties the number of expected properties. * @throws RepositoryException if an error occurs while iterating over the * result nodes. */ protected void checkResult(QueryResult result, int hits, int properties) throws RepositoryException { checkResult(result, hits); // now check property count int count = 0; log.println("Properties:"); String[] propNames = result.getColumnNames(); for (RowIterator it = result.getRows(); it.hasNext();) { StringBuffer msg = new StringBuffer(); Value[] values = it.nextRow().getValues(); for (int i = 0; i < propNames.length; i++, count++) { msg.append(" ").append(propNames[i]).append(": "); if (values[i] == null) { msg.append("null"); } else { msg.append(values[i].getString()); } } log.println(msg); } if (count == 0) { log.println(" NONE"); } assertEquals("Wrong property count.", properties, count); } /** * Checks if the {@link QueryResult} is ordered according order property in * direction of related argument. * * @param queryResult to be tested * @param propName Name of the porperty to order by * @param descending if true order has to be descending * @throws RepositoryException * @throws NotExecutableException in case of less than two results or all * results have same size of value in its * order-property */ protected void evaluateResultOrder(QueryResult queryResult, String propName, boolean descending) throws RepositoryException, NotExecutableException { NodeIterator nodes = queryResult.getNodes(); if (getSize(nodes) < 2) { fail("Workspace does not contain sufficient content to test ordering on result nodes."); } // need to re-aquire nodes, {@link #getSize} may consume elements. nodes = queryResult.getNodes(); int changeCnt = 0; String last = descending ? "\uFFFF" : ""; while (nodes.hasNext()) { String value = nodes.nextNode().getProperty(propName).getString(); int cp = value.compareTo(last); // if value changed evaluate if the ordering is correct if (cp != 0) { changeCnt++; if (cp > 0 && descending) { fail("Repository doesn't order properly descending"); } else if (cp < 0 && !descending) { fail("Repository doesn't order properly ascending"); } } last = value; } if (changeCnt < 1) { fail("Workspace does not contain distinct values for " + propName); } } /** * Executes the xpath query and checks the results against * the specified nodes. * @param session the session to use for the query. * @param xpath the xpath query. * @param expectedNodes the expected nodes. * @throws NotExecutableException */ protected void executeXPathQuery(Session session, String xpath, Node[] expectedNodes) throws RepositoryException, NotExecutableException { QueryResult res = createQuery(session, xpath, qsXPATH).execute(); checkResult(res, expectedNodes, null); } /** * Executes the sql query and checks the results against * the specified nodes. * @param session the session to use for the query. * @param sql the sql query. * @param expectedNodes the expected nodes. * @throws NotExecutableException */ protected void executeSqlQuery(Session session, String sql, Node[] expectedNodes) throws RepositoryException, NotExecutableException { executeSqlQuery(session, sql, expectedNodes, null); } /** * Executes the sql query and checks the results against * the specified nodes. * @param session the session to use for the query. * @param sql the sql query. * @param requiredNodes the nodes that need to be in the result set * (null if no node is required). * @param optionalNodes the nodes that may be in the result set * (null if no node is optional). * @throws NotExecutableException */ protected void executeSqlQuery(Session session, String sql, Node[] requiredNodes, Node[] optionalNodes) throws RepositoryException, NotExecutableException { QueryResult res = createQuery(session, sql, qsSQL).execute(); checkResult(res, requiredNodes, optionalNodes); } /** * Checks if the result set contains exactly the nodes. * @param result the query result. * @param expectedNodes the expected nodes. */ protected void checkResult(QueryResult result, Node[] expectedNodes) throws RepositoryException { checkResult(result, expectedNodes, null); } /** * Checks if the result set contains exactly the nodes. * @param result the query result. * @param requiredNodes the nodes that need to be in the result set * (null if no node is required). * @param optionalNodes the nodes that may be in the result set * (null if no node is optional). */ protected void checkResult(QueryResult result, Node[] requiredNodes, Node[] optionalNodes) throws RepositoryException { // collect paths Set requiredPaths = getPathSet(requiredNodes); Set optionalPaths = getPathSet(optionalNodes); Set resultPaths = new HashSet(); for (NodeIterator it = result.getNodes(); it.hasNext();) { resultPaths.add(it.nextNode().getPath()); } // check if all required nodes are in result for (Iterator it = requiredPaths.iterator(); it.hasNext();) { String path = it.next(); assertTrue(path + " is not part of the result set", resultPaths.contains(path)); } // check result does not contain more than expected for (Iterator it = resultPaths.iterator(); it.hasNext();) { String path = it.next(); if (!optionalPaths.contains(path)) { assertTrue(path + " is not expected to be part of the result set", requiredPaths.contains(path)); } } } private static HashSet getPathSet(Node[] nodes) throws RepositoryException { HashSet paths = new HashSet(); if (nodes != null) { for (int i = 0; i < nodes.length; i++) { paths.add(nodes[i].getPath()); } } return paths; } /** * Returns the nodes in it as an array of Nodes. * @param it the NodeIterator. * @return the elements of the iterator as an array of Nodes. */ protected Node[] toArray(NodeIterator it) { List nodes = new ArrayList(); while (it.hasNext()) { nodes.add(it.nextNode()); } return nodes.toArray(new Node[nodes.size()]); } /** * Escape an identifier suitable for the SQL parser *

* TODO: currently only handles dash character */ protected String escapeIdentifierForSQL(String identifier) { boolean needsEscaping = identifier.indexOf('-') >= 0; if (!needsEscaping) { return identifier; } return '"' + identifier + '"'; } /** * @param language a query language. * @return true if language is supported; * false otherwise. * @throws RepositoryException if an error occurs. */ protected boolean isSupportedLanguage(String language) throws RepositoryException { return Arrays.asList(qm.getSupportedQueryLanguages()).contains(language); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy