| /* |
| * 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.directory.server.core.subtree; |
| |
| |
| import java.util.Iterator; |
| |
| import javax.naming.Name; |
| import javax.naming.NamingException; |
| |
| import org.apache.directory.server.core.entry.ServerEntry; |
| import org.apache.directory.server.core.event.Evaluator; |
| import org.apache.directory.server.core.event.ExpressionEvaluator; |
| import org.apache.directory.server.schema.registries.AttributeTypeRegistry; |
| import org.apache.directory.server.schema.registries.OidRegistry; |
| import org.apache.directory.shared.ldap.name.LdapDN; |
| import org.apache.directory.shared.ldap.subtree.SubtreeSpecification; |
| import org.apache.directory.shared.ldap.util.NamespaceTools; |
| |
| |
| /** |
| * An evaluator used to determine if an entry is included in the collection |
| * represented by a subtree specification. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| * @version $Rev$ |
| */ |
| public class SubtreeEvaluator |
| { |
| /** A refinement filter evaluator */ |
| private final Evaluator evaluator; |
| |
| |
| /** |
| * Creates a subtreeSpecification evaluatior which can be used to determine |
| * if an entry is included within the collection of a subtree. |
| * |
| * @param oidRegistry a registry used to lookup objectClass names for OIDs |
| * @param attrRegistry registry to be looked up |
| * @throws NamingException |
| */ |
| public SubtreeEvaluator( OidRegistry oidRegistry, AttributeTypeRegistry attrRegistry ) |
| { |
| evaluator = new ExpressionEvaluator(oidRegistry, attrRegistry ); |
| } |
| |
| |
| /** |
| * Determines if an entry is selected by a subtree specification. |
| * |
| * @param subtree the subtree specification |
| * @param apDn the distinguished name of the administrative point containing the subentry |
| * @param entryDn the distinguished name of the candidate entry |
| * @return true if the entry is selected by the specification, false if it is not |
| * @throws javax.naming.NamingException if errors are encountered while evaluating selection |
| */ |
| public boolean evaluate( SubtreeSpecification subtree, Name apDn, Name entryDn, ServerEntry entry ) |
| throws NamingException |
| { |
| // TODO: Try to make this cast unnecessary. |
| LdapDN entryLdapDn = (LdapDN) entryDn; |
| |
| /* ===================================================================== |
| * NOTE: Regarding the overall approach, we try to narrow down the |
| * possibilities by slowly pruning relative names off of the entryDn. |
| * For example we check first if the entry is a descendant of the AP. |
| * If so we use the relative name thereafter to calculate if it is |
| * a descendant of the base. This means shorter names to compare and |
| * less work to do while we continue to deduce inclusion by the subtree |
| * specification. |
| * ===================================================================== |
| */ |
| |
| /* |
| * First we simply check if the candidate entry is a descendant of the |
| * administrative point. In the process we calculate the relative |
| * distinguished name relative to the administrative point. |
| */ |
| Name apRelativeRdn; |
| |
| if ( !NamespaceTools.isDescendant( apDn, entryDn ) ) |
| { |
| return false; |
| } |
| else if ( apDn.equals( entryDn ) ) |
| { |
| apRelativeRdn = new LdapDN(); |
| } |
| else |
| { |
| apRelativeRdn = NamespaceTools.getRelativeName( apDn, entryDn ); |
| } |
| |
| /* |
| * We do the same thing with the base as we did with the administrative |
| * point: check if the entry is a descendant of the base and find the |
| * relative name of the entry with respect to the base rdn. With the |
| * baseRelativeRdn we can later make comparisons with specific exclusions. |
| */ |
| Name baseRelativeRdn; |
| |
| if ( subtree.getBase() != null && subtree.getBase().size() == 0 ) |
| { |
| baseRelativeRdn = apRelativeRdn; |
| } |
| else if ( apRelativeRdn.equals( subtree.getBase() ) ) |
| { |
| baseRelativeRdn = new LdapDN(); |
| } |
| else if ( !NamespaceTools.isDescendant( subtree.getBase(), apRelativeRdn ) ) |
| { |
| return false; |
| } |
| else |
| { |
| baseRelativeRdn = NamespaceTools.getRelativeName( subtree.getBase(), apRelativeRdn ); |
| } |
| |
| /* |
| * Evaluate based on minimum and maximum chop values. Here we simply |
| * need to compare the distances respectively with the size of the |
| * baseRelativeRdn. For the max distance entries with a baseRelativeRdn |
| * size greater than the max distance are rejected. For the min distance |
| * entries with a baseRelativeRdn size less than the minimum distance |
| * are rejected. |
| */ |
| if ( subtree.getMaxBaseDistance() != SubtreeSpecification.UNBOUNDED_MAX ) |
| { |
| if ( subtree.getMaxBaseDistance() < baseRelativeRdn.size() ) |
| { |
| return false; |
| } |
| } |
| |
| if ( subtree.getMinBaseDistance() > 0 ) |
| { |
| if ( baseRelativeRdn.size() < subtree.getMinBaseDistance() ) |
| { |
| return false; |
| } |
| } |
| |
| /* |
| * For specific exclusions we must iterate through the set and check |
| * if the baseRelativeRdn is a descendant of the exclusion. The |
| * isDescendant() function will return true if the compared names |
| * are equal so for chopAfter exclusions we must check for equality |
| * as well and reject if the relative names are equal. |
| */ |
| Iterator list = subtree.getChopBeforeExclusions().iterator(); |
| |
| while ( list.hasNext() ) |
| { |
| Name chopBefore = ( Name ) list.next(); |
| |
| if ( NamespaceTools.isDescendant( chopBefore, baseRelativeRdn ) ) |
| { |
| return false; |
| } |
| } |
| |
| list = subtree.getChopAfterExclusions().iterator(); |
| |
| while ( list.hasNext() ) |
| { |
| Name chopAfter = ( Name ) list.next(); |
| |
| if ( NamespaceTools.isDescendant( chopAfter, baseRelativeRdn ) && !chopAfter.equals( baseRelativeRdn ) ) |
| { |
| return false; |
| } |
| } |
| |
| /* |
| * The last remaining step is to check and see if the refinement filter |
| * selects the entry candidate based on objectClass attribute values. |
| * To do this we invoke the refinement evaluator members evaluate() method. |
| */ |
| if ( subtree.getRefinement() != null ) |
| { |
| return evaluator.evaluate( subtree.getRefinement(), entryLdapDn.toNormName(), entry ); |
| } |
| |
| /* |
| * If nothing has rejected the candidate entry and there is no refinement |
| * filter then the entry is included in the collection represented by the |
| * subtree specification so we return true. |
| */ |
| return true; |
| } |
| } |