org.apache.jackrabbit.test.api.query.SQLPathTest Maven / Gradle / Ivy
/*
* 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 javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.NodeIterator;
import javax.jcr.Session;
import javax.jcr.util.TraversingItemVisitor;
import org.apache.jackrabbit.test.NotExecutableException;
import java.util.ArrayList;
import java.util.List;
/**
* Tests path predicates in SQL queries. The default workspace must contain a
* node tree at testroot
with at least two levels.
*
*/
public class SQLPathTest extends AbstractQueryTest {
/** A read-only session */
private Session session;
protected void setUp() throws Exception {
isReadOnly = true;
super.setUp();
session = getHelper().getReadOnlySession();
// check precondition for this test
if (testRootNode.hasNodes()) {
for (NodeIterator it = testRootNode.getNodes(); it.hasNext();) {
if (it.nextNode().hasNodes()) {
return;
}
}
}
fail("Default workspace at " + testRoot + " does not contain sufficient content.");
}
/**
* Releases the session aquired in setUp().
*/
protected void tearDown() throws Exception {
if (session != null) {
session.logout();
session = null;
}
super.tearDown();
}
/**
* Tests if <somepath>/% returns the descendants of <somepath>.
* @throws NotExecutableException
*/
public void testDescendantTestRoot() throws RepositoryException, NotExecutableException {
String sql = getStatement(testRoot + "/%");
executeSqlQuery(session, sql, getDescendants(testRootNode));
}
/**
* Tests if <somepath>/% returns no nodes if node at <somepath>
* is a leaf.
* @throws NotExecutableException
*/
public void testDescendantLeaf() throws RepositoryException, NotExecutableException {
// find leaf
Node leaf = testRootNode;
while (leaf.hasNodes()) {
leaf = leaf.getNodes().nextNode();
}
String sql = getStatement(leaf.getPath() + "/%");
executeSqlQuery(session, sql, new Node[0]);
}
/**
* Tests if <somepath>/%/<nodename> OR <somepath>/<nodename>
* returns nodes with name <nodename> which are descendants of
* node at testroot
.
* @throws NotExecutableException
*/
public void testDescendantSelfTestRoot() throws RepositoryException, NotExecutableException {
// get first node which is two levels deeper than node at testroot
Node n = null;
for (NodeIterator it = testRootNode.getNodes(); it.hasNext();) {
Node child = it.nextNode();
if (child.hasNodes()) {
n = child.getNodes().nextNode();
break;
}
}
final String name = n.getName();
String sql = getStatement(testRoot + "/%/" + name);
sql += " OR " + jcrPath + " = '" + testRoot + "/" + name + "'";
// gather the nodes with visitor
final List nodes = new ArrayList();
testRootNode.accept(new TraversingItemVisitor.Default() {
protected void entering(Node node, int level) throws RepositoryException {
if (node.getName().equals(name) && !testRootNode.isSame(node)) {
nodes.add(node);
}
}
});
executeSqlQuery(session, sql, nodes.toArray(new Node[nodes.size()]));
}
/**
* Tests if /% AND NOT /%/% returns the child nodes of the root node.
* @throws NotExecutableException
*/
public void testChildAxisRoot() throws RepositoryException, NotExecutableException {
String sql = getStatement("/%");
sql += " AND NOT " + jcrPath + " LIKE '/%/%'";
Node[] nodes = toArray(session.getRootNode().getNodes());
// optionally, the result may include the root node -
// the specification allows to not return it even if using jcr:path LIKE '/%'
// see also the JCR 1.0 specification, section 8.5.2.2 ("Pseudo-property jcr:path")
Node[] optional = { session.getRootNode() };
executeSqlQuery(session, sql, nodes, optional);
}
/**
* Tests if <somepath>/% AND NOT <somepath>/%/% returns the child
* nodes of node at <somepath>.
* @throws NotExecutableException
*/
public void testChildAxisTestRoot() throws RepositoryException, NotExecutableException {
String sql = getStatement(testRoot + "/%");
sql += " AND NOT " + jcrPath + " LIKE '" + testRoot + "/%/%'";
Node[] nodes = toArray(testRootNode.getNodes());
executeSqlQuery(session, sql, nodes);
}
/**
* Tests if <somepath>/% AND NOT <somepath>/%/% returns no nodes
* if the node at <somepath> is a leaf.
* @throws NotExecutableException
*/
public void testChildAxisLeaf() throws RepositoryException, NotExecutableException {
// find leaf
Node leaf = testRootNode;
while (leaf.hasNodes()) {
leaf = leaf.getNodes().nextNode();
}
String sql = getStatement(leaf.getPath() + "/%");
sql += " AND NOT " + jcrPath + " LIKE '" + leaf.getPath() + "/%/%'";
executeSqlQuery(session, sql, new Node[0]);
}
//-----------------------------< internal >---------------------------------
/**
* Creates a SQL statement with a path predicate.
* @param path the path
* @return the SQL statement.
*/
private String getStatement(String path) {
return "SELECT * FROM " + ntBase + " WHERE " + jcrPath + " LIKE '" + path + "'";
}
/**
* Returns the descendants of node
as an array in document
* order.
* @param node the starting node.
* @return descendants of node
.
* @throws RepositoryException if an error occurs.
*/
private Node[] getDescendants(final Node node) throws RepositoryException {
final List descendants = new ArrayList();
node.accept(new TraversingItemVisitor.Default() {
protected void entering(Node n, int level)
throws RepositoryException {
if (!node.isSame(n)) {
descendants.add(n);
}
}
});
return descendants.toArray(new Node[descendants.size()]);
}
}