/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.server.core; import static org.opends.server.loggers.Debug.debugConstructor; import static org.opends.server.loggers.Debug.debugEnter; import static org.opends.server.messages.MessageHandler.getMessage; import static org.opends.server.messages.SchemaMessages.*; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.InputMismatchException; import java.util.Iterator; import java.util.NoSuchElementException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.ObjectClass; import org.opends.server.types.ResultCode; import org.opends.server.util.StaticUtils; /** * An RFC 3672 subtree specification. *
* Refer to RFC 3672 for a detailed definition of the subtree
* specification string representation.
*/
public final class RFC3672SubtreeSpecification extends
SimpleSubtreeSpecification {
// Fully qualified class name for debugging purposes.
private static final String CLASS_NAME = RFC3672SubtreeSpecification.class
.getName();
// The root DN.
private DN rootDN;
// The optional relative base DN.
private DN relativeBaseDN;
// The optional specification filter refinements.
private Refinement refinements;
/**
* Abstract interface for RFC3672 specification filter refinements.
*/
public static abstract class Refinement {
/**
* Create a new RFC3672 specification filter refinement.
*/
protected Refinement() {
// No implementation required.
}
/**
* Check if the refinement matches the given entry.
*
* @param entry
* The filterable entry.
* @return Returns true if the entry matches the
* refinement, or false otherwise.
*/
public abstract boolean matches(Entry entry);
/**
* {@inheritDoc}
*/
@Override
public final String toString() {
StringBuilder builder = new StringBuilder();
return toString(builder).toString();
}
/**
* Append the string representation of the refinement to the
* provided string builder.
*
* @param builder
* The string builder.
* @return The string builder.
*/
public abstract StringBuilder toString(StringBuilder builder);
/**
* {@inheritDoc}
*/
@Override
public abstract boolean equals(Object obj);
/**
* {@inheritDoc}
*/
@Override
public abstract int hashCode();
}
/**
* RFC 3672 subtree specification Item refinement. This type of
* refinement filters entries based on the presence of a specified
* object class.
*/
public static final class ItemRefinement extends Refinement {
// The item's object class.
private String objectClass;
// The item's normalized object class.
private String normalizedObjectClass;
/**
* Create a new item refinement.
*
* @param objectClass
* The item's object class.
*/
public ItemRefinement(String objectClass) {
assert debugConstructor(CLASS_NAME);
this.objectClass = objectClass;
this.normalizedObjectClass = StaticUtils.toLowerCase(objectClass
.trim());
}
/**
* {@inheritDoc}
*/
@Override
public boolean matches(Entry entry) {
ObjectClass oc = DirectoryServer
.getObjectClass(normalizedObjectClass);
if (oc == null) {
return false;
} else {
return entry.hasObjectClass(oc);
}
}
/**
* {@inheritDoc}
*/
@Override
public StringBuilder toString(StringBuilder builder) {
builder.append("item:");
builder.append(objectClass);
return builder;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
assert debugEnter(CLASS_NAME, "equals");
if (this == obj) {
return true;
}
if (obj instanceof ItemRefinement) {
ItemRefinement other = (ItemRefinement) obj;
return normalizedObjectClass.equals(other.normalizedObjectClass);
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
assert debugEnter(CLASS_NAME, "hashCode");
return normalizedObjectClass.hashCode();
}
}
/**
* RFC 3672 subtree specification NOT refinement. This type of
* refinement filters entries based on the underlying refinement being
* false.
*/
public static final class NotRefinement extends Refinement {
// The inverted refinement.
private Refinement refinement;
/**
* Create a new NOT refinement.
*
* @param refinement
* The refinement which must be false.
*/
public NotRefinement(Refinement refinement) {
assert debugConstructor(CLASS_NAME);
this.refinement = refinement;
}
/**
* {@inheritDoc}
*/
@Override
public boolean matches(Entry entry) {
return !refinement.matches(entry);
}
/**
* {@inheritDoc}
*/
@Override
public StringBuilder toString(StringBuilder builder) {
builder.append("not:");
return refinement.toString(builder);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj) {
assert debugEnter(CLASS_NAME, "equals");
if (this == obj) {
return true;
}
if (obj instanceof NotRefinement) {
NotRefinement other = (NotRefinement) obj;
return refinement.equals(other.refinement);
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
assert debugEnter(CLASS_NAME, "hashCode");
return refinement.hashCode();
}
}
/**
* RFC 3672 subtree specification AND refinement. This type of
* refinement filters entries based on all of the underlying
* refinements being true.
*/
public static final class AndRefinement extends Refinement {
// The set of refinements which must all be true.
private Collectiontrue.
*/
public AndRefinement(Collectiontrue.
*/
public static final class OrRefinement extends Refinement {
// The set of refinements of which at least one must be true.
private Collectiontrue.
*/
public OrRefinement(Collectionnull if not
* specified).
* @param minimumDepth
* The minimum depth (<=0 means unlimited).
* @param maximumDepth
* The maximum depth (<0 means unlimited).
* @param chopBefore
* The set of chop before local names (relative to the
* relative base DN), or null if there are
* none.
* @param chopAfter
* The set of chop after local names (relative to the
* relative base DN), or null if there are
* none.
* @param refinements
* The optional specification filter refinements, or
* null if there are none.
*/
public RFC3672SubtreeSpecification(DN rootDN, DN relativeBaseDN,
int minimumDepth, int maximumDepth, Iterablenull if none
* was specified.
*/
public DN getRelativeBaseDN() {
assert debugEnter(CLASS_NAME, "getRelativeBaseDN");
return relativeBaseDN;
}
/**
* Get the specification filter refinements.
*
* @return Returns the specification filter refinements, or
* null if none were specified.
*/
public Refinement getRefinements() {
assert debugEnter(CLASS_NAME, "getRefinements");
return refinements;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isWithinScope(Entry entry) {
assert debugEnter(CLASS_NAME, "isWithinScope");
if (isDNWithinScope(entry.getDN())) {
if (refinements != null) {
return refinements.matches(entry);
} else {
return true;
}
} else {
return false;
}
}
/**
* {@inheritDoc}
*/
@Override
public StringBuilder toString(StringBuilder builder) {
assert debugEnter(CLASS_NAME, "toString");
boolean isFirstElement = true;
// Output the optional base DN.
builder.append("{");
if (relativeBaseDN != null && !relativeBaseDN.isNullDN()) {
builder.append(" base ");
StaticUtils.toRFC3641StringValue(builder, relativeBaseDN.toString());
isFirstElement = false;
}
// Output the optional specific exclusions.
Iterable