/* * 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.spi.commons.query; import java.util.Collection; import javax.jcr.RepositoryException; import org.apache.jackrabbit.spi.Name; import org.apache.jackrabbit.spi.commons.name.NameConstants; /** * Implements a query node that defines a path restriction. */ public class PathQueryNode extends NAryQueryNode<LocationStepQueryNode> { /** * Flag indicating whether this path is absolute. */ private boolean absolute = false; /** * Valid node type names under /jcr:system. Used to determine if a * query needs to be executed also against the /jcr:system tree. */ private final Collection<Name> validJcrSystemNodeTypeNames; /** * Empty step node array. */ private static final LocationStepQueryNode[] EMPTY = new LocationStepQueryNode[0]; /** * Creates a relative <code>PathQueryNode</code> with no location steps and * the collection of node types under /jcr:system. * * @param parent the parent query node. * @param validJcrSystemNodeTypeNames valid node types under /jcr:system */ protected PathQueryNode( QueryNode parent, Collection<Name> validJcrSystemNodeTypeNames) { super(parent); this.validJcrSystemNodeTypeNames = validJcrSystemNodeTypeNames; } /** * Returns the collection of valid node types under /jcr:system. * * @return valid node types under /jcr:system. */ public Collection<Name> getValidJcrSystemNodeTypeNames() { return validJcrSystemNodeTypeNames; } /** * {@inheritDoc} * @throws RepositoryException */ public Object accept(QueryNodeVisitor visitor, Object data) throws RepositoryException { return visitor.visit(this, data); } /** * Returns the type of this node. * * @return the type of this node. */ public int getType() { return QueryNode.TYPE_PATH; } /** * Adds a path step to this <code>PathQueryNode</code>. * * @param step the step to add. */ public void addPathStep(LocationStepQueryNode step) { addOperand(step); } /** * Returns an array of all currently set location step nodes. * * @return an array of all currently set location step nodes. */ public LocationStepQueryNode[] getPathSteps() { if (operands == null) { return EMPTY; } else { return operands.toArray(new LocationStepQueryNode[operands.size()]); } } /** * If <code>absolute</code> is <code>true</code> sets this * <code>PathQueryNode</code> to an absolute path. If <code>absolute</code> * is <code>false</code> this path is considered relative. * * @param absolute sets the absolute property to this new value. */ public void setAbsolute(boolean absolute) { this.absolute = absolute; } /** * Returns <code>true</code> if this is an absolute path; <code>false</code> * otherwise. * * @return <code>true</code> if this is an absolute path; <code>false</code> * otherwise. */ public boolean isAbsolute() { return absolute; } /** * {@inheritDoc} */ public boolean equals(Object obj) { if (obj instanceof PathQueryNode) { PathQueryNode other = (PathQueryNode) obj; return super.equals(obj) && absolute == other.absolute; } return false; } /** * {@inheritDoc} */ public boolean needsSystemTree() { LocationStepQueryNode[] pathSteps = getPathSteps(); if (pathSteps == null || pathSteps.length == 0) { return true; } Name firstPathStepName = pathSteps[0].getNameTest(); if (firstPathStepName == null) { // If the first operand of the path steps is a node type query // we do not need to include the system index if the node type is // none of the node types that may occur in the system index. QueryNode[] pathStepOperands = pathSteps[0].getOperands(); if (pathStepOperands.length > 0) { if (pathStepOperands[0] instanceof NodeTypeQueryNode) { NodeTypeQueryNode nodeTypeQueryNode = (NodeTypeQueryNode) pathStepOperands[0]; if (!validJcrSystemNodeTypeNames.contains(nodeTypeQueryNode.getValue())) { return false; } } } // If the first location step has a null name test we need to include // the system tree ("*") return true; } // Calculate the first workspace relative location step LocationStepQueryNode firstWorkspaceRelativeStep = pathSteps[0]; if (firstPathStepName.equals(NameConstants.ROOT)) { // path starts with "/jcr:root" if (pathSteps.length > 1) { firstWorkspaceRelativeStep = pathSteps[1]; } } // First path step starts with "//" if (firstWorkspaceRelativeStep.getIncludeDescendants()) { return true; } // If the first workspace relative location step is jcr:system we need // to include the system tree Name firstWorkspaceRelativeName = firstWorkspaceRelativeStep.getNameTest(); if (firstWorkspaceRelativeName == null || firstWorkspaceRelativeName.equals(NameConstants.JCR_SYSTEM)) { return true; } return super.needsSystemTree(); } }