opendj-server-legacy/src/main/java/org/opends/server/core/SubentryManager.java
@@ -12,11 +12,19 @@ * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2009-2010 Sun Microsystems, Inc. * Portions Copyright 2011-2015 ForgeRock AS. * Portions Copyright 2011-2016 ForgeRock AS. */ package org.opends.server.core; import java.util.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -38,7 +46,14 @@ import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.SearchRequest; import org.opends.server.types.*; import org.opends.server.types.DirectoryException; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.Privilege; import org.opends.server.types.SearchFilter; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SubEntry; import org.opends.server.types.SubtreeSpecification; import org.opends.server.types.operation.PostOperationAddOperation; import org.opends.server.types.operation.PostOperationDeleteOperation; import org.opends.server.types.operation.PostOperationModifyDNOperation; @@ -75,27 +90,22 @@ { private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); /** A mapping between the DNs and applicable subentries. */ private Map<DN,List<SubEntry>> dn2SubEntry; /** A mapping between the DNs and applicable collective subentries. */ private Map<DN,List<SubEntry>> dn2CollectiveSubEntry; /** A mapping between subentry DNs and subentry objects. */ private DITCacheMap<SubEntry> dit2SubEntry; /** Internal search all operational attributes. */ private Set<String> requestAttrs; /** Lock to protect internal data structures. */ private final ReadWriteLock lock; /** The set of change notification listeners. */ private List<SubentryChangeListener> changeListeners; /** Dummy configuration DN for Subentry Manager. */ private static final String CONFIG_DN = "cn=Subentry Manager,cn=config"; /** A mapping between the DNs and applicable subentries. */ private final Map<DN, List<SubEntry>> dn2SubEntry = new HashMap<>(); /** A mapping between the DNs and applicable collective subentries. */ private final Map<DN, List<SubEntry>> dn2CollectiveSubEntry = new HashMap<>(); /** A mapping between subentry DNs and subentry objects. */ private final DITCacheMap<SubEntry> dit2SubEntry = new DITCacheMap<>(); /** Internal search all operational attributes. */ private final Set<String> requestAttrs = newLinkedHashSet("*", "+"); /** Lock to protect internal data structures. */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); /** The set of change notification listeners. */ private final List<SubentryChangeListener> changeListeners = new CopyOnWriteArrayList<>(); /** * Creates a new instance of this subentry manager. * @@ -120,14 +130,6 @@ PluginType.POST_SYNCHRONIZATION_MODIFY_DN), true); lock = new ReentrantReadWriteLock(); dn2SubEntry = new HashMap<>(); dn2CollectiveSubEntry = new HashMap<>(); dit2SubEntry = new DITCacheMap<>(); changeListeners = new CopyOnWriteArrayList<>(); requestAttrs = newLinkedHashSet("*", "+"); DirectoryServer.registerInternalPlugin(this); DirectoryServer.registerBackendInitializationListener(this); } @@ -179,32 +181,17 @@ private void addSubentry(Entry entry) throws DirectoryException { SubEntry subEntry = new SubEntry(entry); SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); DN subDN = subSpec.getBaseDN(); List<SubEntry> subList = null; lock.writeLock().lock(); try { if (subEntry.isCollective() || subEntry.isInheritedCollective()) { subList = dn2CollectiveSubEntry.get(subDN); } else { subList = dn2SubEntry.get(subDN); } Map<DN, List<SubEntry>> subEntryMap = getSubEntryMap(subEntry); List<SubEntry> subList = subEntryMap.get(subDN); if (subList == null) { subList = new ArrayList<>(); if (subEntry.isCollective() || subEntry.isInheritedCollective()) { dn2CollectiveSubEntry.put(subDN, subList); } else { dn2SubEntry.put(subDN, subList); } subEntryMap.put(subDN, subList); } dit2SubEntry.put(entry.getName(), subEntry); subList.add(subEntry); @@ -215,68 +202,25 @@ } } private Map<DN, List<SubEntry>> getSubEntryMap(SubEntry subEntry) { return (subEntry.isCollective() || subEntry.isInheritedCollective()) ? dn2CollectiveSubEntry : dn2SubEntry; } /** * Remove a given entry from this subentry manager. * @param entry to remove. * * @param entry * to remove. */ private void removeSubentry(Entry entry) { lock.writeLock().lock(); try { boolean removed = false; Iterator<Map.Entry<DN, List<SubEntry>>> setIterator = dn2SubEntry.entrySet().iterator(); while (setIterator.hasNext()) if (!removeSubEntry(dn2SubEntry, entry)) { Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next(); List<SubEntry> subList = mapEntry.getValue(); Iterator<SubEntry> listIterator = subList.iterator(); while (listIterator.hasNext()) { SubEntry subEntry = listIterator.next(); if (subEntry.getDN().equals(entry.getName())) { dit2SubEntry.remove(entry.getName()); listIterator.remove(); removed = true; break; } } if (subList.isEmpty()) { setIterator.remove(); } if (removed) { return; } } setIterator = dn2CollectiveSubEntry.entrySet().iterator(); while (setIterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next(); List<SubEntry> subList = mapEntry.getValue(); Iterator<SubEntry> listIterator = subList.iterator(); while (listIterator.hasNext()) { SubEntry subEntry = listIterator.next(); if (subEntry.getDN().equals(entry.getName())) { dit2SubEntry.remove(entry.getName()); listIterator.remove(); removed = true; break; } } if (subList.isEmpty()) { setIterator.remove(); } if (removed) { return; } removeSubEntry(dn2CollectiveSubEntry, entry); } } finally @@ -285,6 +229,31 @@ } } private boolean removeSubEntry(Map<DN, List<SubEntry>> subEntryMap, Entry entry) { Iterator<List<SubEntry>> subEntryListsIt = subEntryMap.values().iterator(); while (subEntryListsIt.hasNext()) { List<SubEntry> subEntries = subEntryListsIt.next(); Iterator<SubEntry> subEntriesIt = subEntries.iterator(); while (subEntriesIt.hasNext()) { SubEntry subEntry = subEntriesIt.next(); if (subEntry.getDN().equals(entry.getName())) { dit2SubEntry.remove(entry.getName()); subEntriesIt.remove(); if (subEntries.isEmpty()) { subEntryListsIt.remove(); } return true; } } } return false; } /** * {@inheritDoc} In this case, the server will search the backend to find * all subentries that it may contain and register them with this manager. @@ -417,31 +386,33 @@ * Return subentries applicable to specific DN. * Note that this getter will skip any collective subentries, * returning only applicable regular subentries. * @param dn for which to retrieve applicable * subentries. * @param dn for which to retrieve applicable subentries. * @return applicable subentries. */ public List<SubEntry> getSubentries(DN dn) { if (dn2SubEntry.isEmpty()) return getSubentries(dn2SubEntry, dn); } private List<SubEntry> getSubentries(Map<DN, List<SubEntry>> subEntryMap, DN dn) { if (subEntryMap.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<>(); lock.readLock().lock(); try { for (DN subDN = dn; subDN != null; subDN = subDN.parent()) List<SubEntry> subentries = new ArrayList<>(); for (DN subDN = dn; subDN != null; subDN = subDN.parent()) { List<SubEntry> subList = dn2SubEntry.get(subDN); List<SubEntry> subList = subEntryMap.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isDNWithinScope(dn)) { subentries.add(subEntry); @@ -449,13 +420,12 @@ } } } return subentries; } finally { lock.readLock().unlock(); } return subentries; } /** @@ -468,26 +438,28 @@ */ public List<SubEntry> getSubentries(Entry entry) { if (dn2SubEntry.isEmpty()) return getSubentries(dn2SubEntry, entry); } private List<SubEntry> getSubentries(Map<DN, List<SubEntry>> subEntryMap, Entry entry) { if (subEntryMap.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<>(); lock.readLock().lock(); try { for (DN subDN = entry.getName(); subDN != null; subDN = subDN.parent()) List<SubEntry> subentries = new ArrayList<>(); for (DN subDN = entry.getName(); subDN != null; subDN = subDN.parent()) { List<SubEntry> subList = dn2SubEntry.get(subDN); List<SubEntry> subList = subEntryMap.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isWithinScope(entry)) { subentries.add(subEntry); @@ -495,13 +467,12 @@ } } } return subentries; } finally { lock.readLock().unlock(); } return subentries; } /** @@ -514,40 +485,7 @@ */ public List<SubEntry> getCollectiveSubentries(DN dn) { if (dn2CollectiveSubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<>(); lock.readLock().lock(); try { for (DN subDN = dn; subDN != null; subDN = subDN.parent()) { List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isDNWithinScope(dn)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; return getSubentries(dn2CollectiveSubEntry, dn); } /** @@ -560,40 +498,7 @@ */ public List<SubEntry> getCollectiveSubentries(Entry entry) { if (dn2CollectiveSubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<>(); lock.readLock().lock(); try { for (DN subDN = entry.getName(); subDN != null; subDN = subDN.parent()) { List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isWithinScope(entry)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; return getSubentries(dn2CollectiveSubEntry, entry); } /** @@ -606,77 +511,8 @@ lock.writeLock().lock(); try { Iterator<Map.Entry<DN, List<SubEntry>>> setIterator = dn2SubEntry.entrySet().iterator(); while (setIterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next(); List<SubEntry> subList = mapEntry.getValue(); Iterator<SubEntry> listIterator = subList.iterator(); while (listIterator.hasNext()) { SubEntry subEntry = listIterator.next(); if (backend.handlesEntry(subEntry.getDN())) { dit2SubEntry.remove(subEntry.getDN()); listIterator.remove(); // Notify change listeners. for (SubentryChangeListener changeListener : changeListeners) { try { changeListener.handleSubentryDelete( subEntry.getEntry()); } catch (Exception e) { logger.traceException(e); } } } } if (subList.isEmpty()) { setIterator.remove(); } } setIterator = dn2CollectiveSubEntry.entrySet().iterator(); while (setIterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = setIterator.next(); List<SubEntry> subList = mapEntry.getValue(); Iterator<SubEntry> listIterator = subList.iterator(); while (listIterator.hasNext()) { SubEntry subEntry = listIterator.next(); if (backend.handlesEntry(subEntry.getDN())) { dit2SubEntry.remove(subEntry.getDN()); listIterator.remove(); // Notify change listeners. for (SubentryChangeListener changeListener : changeListeners) { try { changeListener.handleSubentryDelete( subEntry.getEntry()); } catch (Exception e) { logger.traceException(e); } } } } if (subList.isEmpty()) { setIterator.remove(); } } performBackendPostFinalizationProcessing(dn2SubEntry, backend); performBackendPostFinalizationProcessing(dn2CollectiveSubEntry, backend); } finally { @@ -684,6 +520,42 @@ } } private void performBackendPostFinalizationProcessing(Map<DN, List<SubEntry>> subEntryMap, Backend<?> backend) { Iterator<List<SubEntry>> subEntryListsIt = subEntryMap.values().iterator(); while (subEntryListsIt.hasNext()) { List<SubEntry> subEntryList = subEntryListsIt.next(); Iterator<SubEntry> subEntriesIt = subEntryList.iterator(); while (subEntriesIt.hasNext()) { SubEntry subEntry = subEntriesIt.next(); if (backend.handlesEntry(subEntry.getDN())) { dit2SubEntry.remove(subEntry.getDN()); subEntriesIt.remove(); // Notify change listeners. for (SubentryChangeListener changeListener : changeListeners) { try { changeListener.handleSubentryDelete(subEntry.getEntry()); } catch (Exception e) { logger.traceException(e); } } } } if (subEntryList.isEmpty()) { subEntryListsIt.remove(); } } } @Override public void performBackendPostInitializationProcessing(Backend<?> backend) { // Nothing to do. @@ -860,7 +732,6 @@ } } /** {@inheritDoc} */ @Override public PreOperation doPreOperation( PreOperationAddOperation addOperation) @@ -898,7 +769,6 @@ return PluginResult.PreOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PreOperation doPreOperation( PreOperationDeleteOperation deleteOperation) @@ -950,7 +820,6 @@ return PluginResult.PreOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PreOperation doPreOperation( PreOperationModifyOperation modifyOperation) @@ -991,7 +860,6 @@ return PluginResult.PreOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PreOperation doPreOperation(PreOperationModifyDNOperation modifyDNOperation) { @@ -1049,7 +917,6 @@ return PluginResult.PreOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationAddOperation addOperation) @@ -1065,7 +932,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationDeleteOperation deleteOperation) @@ -1081,7 +947,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationModifyOperation modifyOperation) @@ -1098,7 +963,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public PostOperation doPostOperation( PostOperationModifyDNOperation modifyDNOperation) @@ -1115,7 +979,6 @@ return PluginResult.PostOperation.continueOperationProcessing(); } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationAddOperation addOperation) @@ -1127,7 +990,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationDeleteOperation deleteOperation) @@ -1139,7 +1001,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationModifyOperation modifyOperation) @@ -1152,7 +1013,6 @@ } } /** {@inheritDoc} */ @Override public void doPostSynchronization( PostSynchronizationModifyDNOperation modifyDNOperation) opendj-server-legacy/src/main/java/org/opends/server/types/SubEntry.java
@@ -26,6 +26,7 @@ import org.opends.server.core.DirectoryServer; import static org.opends.messages.SchemaMessages.*; import static org.opends.server.types.SubEntry.CollectiveConflictBehavior.*; import static org.opends.server.util.ServerConstants.*; /** @@ -73,7 +74,6 @@ this.name = name; } /** {@inheritDoc} */ @Override public String toString() { @@ -81,57 +81,26 @@ } } /** * The name of the "collectiveConflictBehavior" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR = "collectiveconflictbehavior"; /** * The name of the "inheritFromDNAttribute" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN = "inheritfromdnattribute"; /** * The name of the "inheritFromRDNAttribute" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN = "inheritfromrdnattribute"; /** * The name of the "inheritFromRDNType" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE = "inheritfromrdntype"; /** * The name of the "inheritFromBaseRDN" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE = "inheritfrombaserdn"; /** * The name of the "inheritAttribute" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_INHERIT_COLLECTIVE_ATTR = "inheritattribute"; /** The lowercased name of the "collectiveConflictBehavior" attribute type. */ public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC = "collectiveconflictbehavior"; /** The lowercased name of the "inheritFromDNAttribute" attribute type. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_DN_LC = "inheritfromdnattribute"; /** The lowercased name of the "inheritFromRDNAttribute" attribute type. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC = "inheritfromrdnattribute"; /** The lowercased name of the "inheritFromRDNType" attribute type. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC = "inheritfromrdntype"; /** The lowercased name of the "inheritFromBaseRDN" attribute type. */ public static final String ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC = "inheritfrombaserdn"; /** The lowercased name of the "inheritAttribute" attribute type. */ public static final String ATTR_INHERIT_COLLECTIVE_ATTR_LC = "inheritattribute"; /** Attribute option to mark attributes collective. */ private static final String ATTR_OPTION_COLLECTIVE = "collective"; private static final String ATTR_OPTION_COLLECTIVE = "collective"; /** Entry object. */ private Entry entry; /** Subtree specification. */ private SubtreeSpecification subTreeSpec; private final SubtreeSpecification subTreeSpec; /** Collective subentry flag. */ private boolean isCollective; @@ -158,11 +127,10 @@ private DN inheritFromBaseDN; /** Collective attributes. */ private List<Attribute> collectiveAttributes; private final List<Attribute> collectiveAttributes = new ArrayList<>(); /** Conflict behavior. */ private CollectiveConflictBehavior conflictBehavior = CollectiveConflictBehavior.REAL_OVERRIDES_VIRTUAL; private CollectiveConflictBehavior conflictBehavior = REAL_OVERRIDES_VIRTUAL; /** * Constructs a subentry object from a given entry object. @@ -174,73 +142,17 @@ { this.entry = entry; // Process subtree specification. this.subTreeSpec = null; String specString = null; boolean isValidSpec = true; AttributeType specAttrType = DirectoryServer.getAttributeType(ATTR_SUBTREE_SPEC_LC); for (Attribute attr : entry.getAttribute(specAttrType)) { for (ByteString value : attr) { specString = value.toString(); try { this.subTreeSpec = SubtreeSpecification.valueOf(entry.getName().parent(), specString); isValidSpec = true; } catch (DirectoryException de) { isValidSpec = false; } if (this.subTreeSpec != null) { break; } } if (this.subTreeSpec != null) { break; } } // Check that the subtree spec is flagged as valid. If it is not // that means all parsers have failed and it is invalid syntax. if (!isValidSpec) { LocalizableMessage message = ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get( specString); throw new DirectoryException( ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } // Subentry has to to have a subtree specification. if (this.subTreeSpec == null) { // There is none for some reason eg this could be // old Draft based ldapSubEntry so create a dummy. this.subTreeSpec = new SubtreeSpecification(entry.getName().parent(), null, -1, -1, null, null, null); } // Determine if this subentry is collective attribute subentry. this.subTreeSpec = buildSubTreeSpecification(entry); this.isCollective = entry.isCollectiveAttributeSubentry(); // Determine if this subentry is inherited collective // attribute subentry and if so what kind. this.isInheritedCollective = entry.isInheritedCollectiveAttributeSubentry(); this.isInheritedCollective = entry.isInheritedCollectiveAttributeSubentry(); if (this.isInheritedCollective) { this.isInheritedFromDNCollective = entry.isInheritedFromDNCollectiveAttributeSubentry(); this.isInheritedFromRDNCollective = entry.isInheritedFromRDNCollectiveAttributeSubentry(); this.isInheritedFromDNCollective = entry.isInheritedFromDNCollectiveAttributeSubentry(); this.isInheritedFromRDNCollective = entry.isInheritedFromRDNCollectiveAttributeSubentry(); } // Process collective attributes. this.collectiveAttributes = new ArrayList<>(); if (this.isCollective) { List<Attribute> subAttrList = entry.getAttributes(); @@ -249,9 +161,7 @@ AttributeType attrType = subAttr.getAttributeDescription().getAttributeType(); if (attrType.isCollective()) { CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(subAttr); this.collectiveAttributes.add(collectiveAttr); this.collectiveAttributes.add(new CollectiveVirtualAttribute(subAttr)); } else if (subAttr.hasOption(ATTR_OPTION_COLLECTIVE)) { @@ -259,14 +169,13 @@ builder.addAll(subAttr); for (String option : subAttr.getAttributeDescription().getOptions()) { if (!option.equals(ATTR_OPTION_COLLECTIVE)) if (!ATTR_OPTION_COLLECTIVE.equals(option)) { builder.setOption(option); } } Attribute attr = builder.toAttribute(); CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(attr); this.collectiveAttributes.add(collectiveAttr); this.collectiveAttributes.add(new CollectiveVirtualAttribute(attr)); } } } @@ -276,7 +185,7 @@ { if (this.isInheritedFromDNCollective) { for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_DN)) for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_DN_LC)) { for (ByteString value : attr) { @@ -289,7 +198,7 @@ if (this.isInheritedFromRDNCollective) { for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN)) for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_LC)) { for (ByteString value : attr) { @@ -298,7 +207,7 @@ break; } } for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE)) for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_RDN_TYPE_LC)) { for (ByteString value : attr) { @@ -306,7 +215,7 @@ break; } } for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE)) for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_FROM_BASE_LC)) { for (ByteString value : attr) { @@ -318,13 +227,12 @@ } } for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_ATTR)) for (Attribute attr : entry.getAttribute(ATTR_INHERIT_COLLECTIVE_ATTR_LC)) { for (ByteString value : attr) { CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(Attributes.empty(value.toString())); this.collectiveAttributes.add(collectiveAttr); Attribute collectiveAttr = Attributes.empty(value.toString()); this.collectiveAttributes.add(new CollectiveVirtualAttribute(collectiveAttr)); } } } @@ -332,7 +240,7 @@ // Establish collective attribute conflict behavior. if (this.isCollective || this.isInheritedCollective) { for (Attribute attr : entry.getAttribute(ATTR_COLLECTIVE_CONFLICT_BEHAVIOR)) for (Attribute attr : entry.getAttribute(ATTR_COLLECTIVE_CONFLICT_BEHAVIOR_LC)) { for (ByteString value : attr) { @@ -349,6 +257,46 @@ } } private SubtreeSpecification buildSubTreeSpecification(Entry entry) throws DirectoryException { String specString = null; boolean isValidSpec = true; AttributeType specAttrType = DirectoryServer.getAttributeType(ATTR_SUBTREE_SPEC_LC); for (Attribute attr : entry.getAttribute(specAttrType)) { for (ByteString value : attr) { specString = value.toString(); try { SubtreeSpecification subTreeSpec = SubtreeSpecification.valueOf(entry.getName().parent(), specString); if (subTreeSpec != null) { return subTreeSpec; } isValidSpec = true; } catch (DirectoryException ignored) { isValidSpec = false; } } } // Check that the subtree spec is flagged as valid. If it is not // that means all parsers have failed and it is invalid syntax. if (!isValidSpec) { LocalizableMessage message = ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(specString); throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } // Subentry has to have a subtree specification. // There is none for some reason eg this could be // old Draft based ldapSubEntry so create a dummy. return new SubtreeSpecification(entry.getName().parent(), null, -1, -1, null, null, null); } /** * Retrieves the distinguished name for this subentry. * @return The distinguished name for this subentry. @@ -359,8 +307,7 @@ } /** * Getter to retrieve the actual entry object * for this subentry. * Getter to retrieve the actual entry object for this subentry. * @return entry object for this subentry. */ public final Entry getEntry() @@ -369,10 +316,8 @@ } /** * Indicates whether or not this subentry is * a collective attribute subentry. * @return <code>true</code> if collective, * <code>false</code> otherwise. * Indicates whether this subentry is a collective attribute subentry. * @return {@code true} if collective, {@code false} otherwise. */ public boolean isCollective() { @@ -380,11 +325,8 @@ } /** * Indicates whether or not this subentry is * an inherited collective attribute subentry. * @return <code>true</code> if inherited * collective, <code>false</code> * otherwise. * Indicates whether this subentry is inherited collective attribute subentry. * @return {@code true} if inherited collective, {@code false} otherwise. */ public boolean isInheritedCollective() { @@ -392,12 +334,8 @@ } /** * Indicates whether or not this subentry is * an inherited from DN collective attribute * subentry. * @return <code>true</code> if inherited * from DN collective, * <code>false</code> otherwise. * Indicates whether this subentry is inherited from DN collective attribute subentry. * @return {@code true} if inherited from DN collective, {@code false} otherwise. */ public boolean isInheritedFromDNCollective() { @@ -405,12 +343,8 @@ } /** * Indicates whether or not this subentry is * an inherited from RDN collective attribute * subentry. * @return <code>true</code> if inherited * from RDN collective, * <code>false</code> otherwise. * Indicates whether this subentry is inherited from RDN collective attribute subentry. * @return {@code true} if inherited from RDN collective, {@code false} otherwise. */ public boolean isInheritedFromRDNCollective() { @@ -418,10 +352,8 @@ } /** * Getter to retrieve inheritFromDNAttribute type * for inherited collective attribute subentry. * @return Type of inheritFromDNAttribute or, * <code>null</code> if there is none. * Getter to retrieve inheritFromDNAttribute type for inherited collective attribute subentry. * @return Type of inheritFromDNAttribute, or {@code null} if there is none. */ public AttributeType getInheritFromDNType() { @@ -429,10 +361,8 @@ } /** * Getter to retrieve inheritFromRDNAttribute type * for inherited collective attribute subentry. * @return Type of inheritFromRDNAttribute or, * <code>null</code> if there is none. * Getter to retrieve inheritFromRDNAttribute type for inherited collective attribute subentry. * @return Type of inheritFromRDNAttribute, or {@code null} if there is none. */ public AttributeType getInheritFromRDNAttrType() { @@ -440,10 +370,8 @@ } /** * Getter to retrieve inheritFromRDNAttribute value * for inherited collective attribute subentry. * @return ByteString of inheritFromRDNAttribute * or, <code>null</code> if there is none. * Getter to retrieve inheritFromRDNAttribute value for inherited collective attribute subentry. * @return ByteString of inheritFromRDNAttribute, or {@code null} if there is none. */ public ByteString getInheritFromRDNAttrValue() { @@ -451,10 +379,8 @@ } /** * Getter to retrieve RDN type of inheritFromRDNType * for inherited collective attribute subentry. * @return RDN Type of inheritFromRDNAttribute or, * <code>null</code> if there is none. * Getter to retrieve RDN type of inheritFromRDNType for inherited collective attribute subentry. * @return RDN Type of inheritFromRDNAttribute, or {@code null} if there is none. */ public AttributeType getInheritFromRDNType() { @@ -462,10 +388,8 @@ } /** * Getter to retrieve inheritFromDNAttribute value * for inherited collective attribute subentry. * @return ByteString of inheritFromDNAttribute * or, <code>null</code> if there is none. * Getter to retrieve inheritFromDNAttribute value for inherited collective attribute subentry. * @return ByteString of inheritFromDNAttribute, or {@code null} if there is none. */ public ByteString getInheritFromDNAttrValue() { @@ -473,10 +397,8 @@ } /** * Getter to retrieve inheritFromBaseRDN DN * for inherited collective attribute subentry. * @return DN of inheritFromBaseRDN or, * <code>null</code> if there is none. * Getter to retrieve inheritFromBaseRDN DN for inherited collective attribute subentry. * @return DN of inheritFromBaseRDN, or {@code null} if there is none. */ public DN getInheritFromBaseDN() { @@ -502,13 +424,17 @@ } /** * Getter for collective conflict behavior defined for this * collective attributes subentry. * @return conflict behavior for this collective attributes * subentry. * Getter for collective conflict behavior defined for this collective attributes subentry. * @return conflict behavior for this collective attributes subentry. */ public CollectiveConflictBehavior getConflictBehavior() { return this.conflictBehavior; } @Override public String toString() { return getClass().getSimpleName() + "(" + this.entry.getName() + ")"; } } opendj-server-legacy/src/main/java/org/opends/server/types/SubtreeSpecification.java
@@ -16,7 +16,18 @@ */ package org.opends.server.types; import java.util.*; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.InputMismatchException; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Scanner; import java.util.Set; import java.util.TreeMap; import java.util.regex.Pattern; import org.forgerock.i18n.LocalizableMessage; @@ -61,8 +72,6 @@ /** The set of refinements which must all be true. */ private final Collection<Refinement> refinementSet; /** * Create a new AND refinement. * @@ -75,9 +84,6 @@ this.refinementSet = refinementSet; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { @@ -96,18 +102,12 @@ return false; } /** {@inheritDoc} */ @Override public int hashCode() { return refinementSet.hashCode(); } /** {@inheritDoc} */ @Override public boolean matches(final Entry entry) { @@ -123,9 +123,6 @@ return true; } /** {@inheritDoc} */ @Override public StringBuilder toString(final StringBuilder builder) { @@ -155,18 +152,12 @@ } } /** * A refinement which uses a search filter. */ /** A refinement which uses a search filter. */ public static final class FilterRefinement extends Refinement { /** The search filter. */ private final SearchFilter filter; /** * Create a new filter refinement. * @@ -178,9 +169,6 @@ this.filter = filter; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { @@ -198,18 +186,12 @@ return false; } /** {@inheritDoc} */ @Override public int hashCode() { return filter.hashCode(); } /** {@inheritDoc} */ @Override public boolean matches(final Entry entry) { @@ -225,9 +207,6 @@ } } /** {@inheritDoc} */ @Override public StringBuilder toString(final StringBuilder builder) { @@ -236,8 +215,6 @@ } } /** * RFC 3672 subtree specification Item refinement. This type of * refinement filters entries based on the presence of a specified @@ -251,8 +228,6 @@ /** The item's normalized object class. */ private final String normalizedObjectClass; /** * Create a new item refinement. * @@ -266,9 +241,6 @@ .toLowerCase(objectClass.trim()); } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { @@ -288,18 +260,12 @@ return false; } /** {@inheritDoc} */ @Override public int hashCode() { return normalizedObjectClass.hashCode(); } /** {@inheritDoc} */ @Override public boolean matches(final Entry entry) { @@ -307,9 +273,6 @@ return oc != null && entry.hasObjectClass(oc); } /** {@inheritDoc} */ @Override public StringBuilder toString(final StringBuilder builder) { @@ -319,8 +282,6 @@ } } /** * RFC 3672 subtree specification NOT refinement. This type of * refinement filters entries based on the underlying refinement @@ -332,8 +293,6 @@ /** The inverted refinement. */ private final Refinement refinement; /** * Create a new NOT refinement. * @@ -345,9 +304,6 @@ this.refinement = refinement; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { @@ -366,27 +322,18 @@ return false; } /** {@inheritDoc} */ @Override public int hashCode() { return refinement.hashCode(); } /** {@inheritDoc} */ @Override public boolean matches(final Entry entry) { return !refinement.matches(entry); } /** {@inheritDoc} */ @Override public StringBuilder toString(final StringBuilder builder) { @@ -395,8 +342,6 @@ } } /** * RFC 3672 subtree specification OR refinement. This type of * refinement filters entries based on at least one of the @@ -407,8 +352,6 @@ /** The set of refinements of which at least one must be true. */ private final Collection<Refinement> refinementSet; /** * Create a new OR refinement. * @@ -421,9 +364,6 @@ this.refinementSet = refinementSet; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { @@ -442,18 +382,12 @@ return false; } /** {@inheritDoc} */ @Override public int hashCode() { return refinementSet.hashCode(); } /** {@inheritDoc} */ @Override public boolean matches(final Entry entry) { @@ -469,9 +403,6 @@ return false; } /** {@inheritDoc} */ @Override public StringBuilder toString(final StringBuilder builder) { @@ -501,35 +432,21 @@ } } /** * Abstract interface for RFC3672 specification filter refinements. */ /** Abstract interface for RFC3672 specification filter refinements. */ public static abstract class Refinement { /** * Create a new RFC3672 specification filter refinement. */ /** Create a new RFC3672 specification filter refinement. */ protected Refinement() { // No implementation required. } /** {@inheritDoc} */ @Override public abstract boolean equals(Object obj); /** {@inheritDoc} */ @Override public abstract int hashCode(); /** * Check if the refinement matches the given entry. * @@ -540,9 +457,6 @@ */ public abstract boolean matches(Entry entry); /** {@inheritDoc} */ @Override public final String toString() { @@ -551,8 +465,6 @@ return toString(builder).toString(); } /** * Append the string representation of the refinement to the * provided strin builder. @@ -564,8 +476,6 @@ public abstract StringBuilder toString(StringBuilder builder); } /** * Internal utility class which can be used by sub-classes to help * parse string representations. @@ -605,8 +515,6 @@ private static Pattern STRING_VALUE_TOKEN = Pattern .compile("\"([^\"]|(\"\"))*\""); /** * Create a new parser for a subtree specification string value. * @@ -618,8 +526,6 @@ this.scanner = new Scanner(value); } /** * Determine if there are remaining tokens. * @@ -631,8 +537,6 @@ return scanner.hasNext(); } /** * Determine if the next token is a right-brace character. * @@ -644,8 +548,6 @@ return scanner.hasNext(RBRACE); } /** * Scans the next token of the input as a non-negative * <code>int</code> value. @@ -664,8 +566,6 @@ return Integer.parseInt(s); } /** * Scans the next token of the input as a key value. * @@ -681,8 +581,6 @@ return StaticUtils.toLowerCase(scanner.next()); } /** * Scans the next token of the input as a name value. * <p> @@ -701,8 +599,6 @@ return nextValue(NAME, NAME_TOKEN); } /** * Scans the next tokens of the input as a set of specific * exclusions encoded according to the SpecificExclusion @@ -724,7 +620,6 @@ final Set<DN> chopAfter) throws InputMismatchException, NoSuchElementException, DirectoryException { // Skip leading open-brace. skipLeftBrace(); @@ -754,11 +649,11 @@ // <type>:<value>. final String type = StaticUtils.toLowerCase(nextName()); skipColon(); if (type.equals("chopbefore")) if ("chopbefore".equals(type)) { chopBefore.add(DN.valueOf(nextStringValue())); } else if (type.equals("chopafter")) else if ("chopafter".equals(type)) { chopAfter.add(DN.valueOf(nextStringValue())); } @@ -769,8 +664,6 @@ } } /** * Scans the next token of the input as a string quoted according * to the StringValue production in RFC 3641. @@ -791,8 +684,6 @@ return s.substring(1, s.length() - 1).replace("\"\"", "\""); } /** * Skip a colon separator. * @@ -807,8 +698,6 @@ nextValue(COLON, COLON_TOKEN); } /** * Skip a left-brace character. * @@ -823,8 +712,6 @@ nextValue(LBRACE, LBRACE_TOKEN); } /** * Skip a right-brace character. * @@ -839,8 +726,6 @@ nextValue(RBRACE, RBRACE_TOKEN); } /** * Skip a comma separator. * @@ -855,8 +740,6 @@ nextValue(SEP, SEP_TOKEN); } /** * Parse the next token from the string using the specified * patterns. @@ -898,8 +781,6 @@ } } /** * Parses the string argument as an RFC3672 subtree specification. * @@ -916,7 +797,6 @@ public static SubtreeSpecification valueOf(final DN rootDN, final String s) throws DirectoryException { // Default values. DN relativeBaseDN = null; @@ -965,7 +845,7 @@ } final String key = parser.nextKey(); if (key.equals("base")) if ("base".equals(key)) { if (relativeBaseDN != null) { @@ -974,7 +854,7 @@ } relativeBaseDN = DN.valueOf(parser.nextStringValue()); } else if (key.equals("minimum")) else if ("minimum".equals(key)) { if (minimum != -1) { @@ -983,7 +863,7 @@ } minimum = parser.nextInt(); } else if (key.equals("maximum")) else if ("maximum".equals(key)) { if (maximum != -1) { @@ -992,7 +872,7 @@ } maximum = parser.nextInt(); } else if (key.equals("specificationfilter")) else if ("specificationfilter".equals(key)) { if (refinement != null) { @@ -1000,8 +880,7 @@ throw new InputMismatchException(); } // First try normal search filter before RFC3672 // refinements. // First try normal search filter before RFC3672 refinements. try { final SearchFilter filter = SearchFilter @@ -1013,7 +892,7 @@ refinement = parseRefinement(parser); } } else if (key.equals("specificexclusions")) else if ("specificexclusions".equals(key)) { if (!chopBefore.isEmpty() || !chopAfter.isEmpty()) { @@ -1046,22 +925,16 @@ isValid = false; } if (isValid) { return new SubtreeSpecification(rootDN, relativeBaseDN, minimum, maximum, chopBefore, chopAfter, refinement); } else if (!isValid) { final LocalizableMessage message = ERR_ATTR_SYNTAX_RFC3672_SUBTREE_SPECIFICATION_INVALID.get(s); throw new DirectoryException( ResultCode.INVALID_ATTRIBUTE_SYNTAX, message); } return new SubtreeSpecification(rootDN, relativeBaseDN, minimum, maximum, chopBefore, chopAfter, refinement); } /** * Parse a single refinement. * @@ -1082,26 +955,21 @@ // Skip the colon separator. parser.skipColon(); if (type.equals("item")) if ("item".equals(type)) { return new ItemRefinement(parser.nextName()); } else if (type.equals("not")) else if ("not".equals(type)) { final Refinement refinement = parseRefinement(parser); return new NotRefinement(refinement); return new NotRefinement(parseRefinement(parser)); } else if (type.equals("and")) else if ("and".equals(type)) { final ArrayList<Refinement> refinements = parseRefinementSet(parser); return new AndRefinement(refinements); return new AndRefinement(parseRefinementSet(parser)); } else if (type.equals("or")) else if ("or".equals(type)) { final ArrayList<Refinement> refinements = parseRefinementSet(parser); return new OrRefinement(refinements); return new OrRefinement(parseRefinementSet(parser)); } else { @@ -1110,8 +978,6 @@ } } /** * Parse a list of refinements. * @@ -1155,15 +1021,12 @@ } // Parse each sub-refinement. final Refinement refinement = parseRefinement(parser); refinements.add(refinement); refinements.add(parseRefinement(parser)); } return refinements; } /** The absolute base of the subtree. */ private final DN baseDN; @@ -1187,8 +1050,6 @@ /** The optional specification filter refinements. */ private final Refinement refinements; /** * Create a new RFC3672 subtree specification. * @@ -1260,8 +1121,6 @@ this.refinements = refinements; } /** * Indicates whether the provided object is logically equal to this * subtree specification object. @@ -1275,7 +1134,6 @@ @Override public boolean equals(final Object obj) { if (this == obj) { return true; @@ -1285,31 +1143,17 @@ { final SubtreeSpecification other = (SubtreeSpecification) obj; if (!commonComponentsEquals(other)) { return false; } if (!getBaseDN().equals(other.getBaseDN())) { return false; } if (refinements != null) { return refinements.equals(other.refinements); } else { return refinements == other.refinements; } return minimumDepth == other.minimumDepth && maximumDepth == other.maximumDepth && chopBefore.values().equals(other.chopBefore.values()) && chopAfter.values().equals(other.chopAfter.values()) && getBaseDN().equals(other.getBaseDN()) && Objects.equals(refinements, other.refinements); } return false; } /** * Get the absolute base DN of the subtree specification. * @@ -1321,8 +1165,6 @@ return baseDN; } /** * Get the set of chop after relative DNs. * @@ -1330,12 +1172,9 @@ */ public Iterable<DN> getChopAfter() { return chopAfter.values(); } /** * Get the set of chop before relative DNs. * @@ -1343,12 +1182,9 @@ */ public Iterable<DN> getChopBefore() { return chopBefore.values(); } /** * Get the maximum depth of the subtree specification. * @@ -1359,8 +1195,6 @@ return maximumDepth; } /** * Get the minimum depth of the subtree specification. * @@ -1372,8 +1206,6 @@ return minimumDepth; } /** * Get the specification filter refinements. * @@ -1385,8 +1217,6 @@ return refinements; } /** * Get the relative base DN. * @@ -1398,8 +1228,6 @@ return relativeBaseDN; } /** * Get the root DN. * @@ -1410,8 +1238,6 @@ return rootDN; } /** * Retrieves the hash code for this subtree specification object. * @@ -1420,9 +1246,9 @@ @Override public int hashCode() { int hash = commonComponentsHashCode(); int hash = minimumDepth * 31 + maximumDepth; hash = hash * 31 + chopBefore.values().hashCode(); hash = hash * 31 + chopAfter.values().hashCode(); hash = hash * 31 + getBaseDN().hashCode(); if (refinements != null) @@ -1433,8 +1259,6 @@ return hash; } /** * Determine if the specified DN is within the scope of the subtree * specification. @@ -1447,7 +1271,6 @@ */ public boolean isDNWithinScope(final DN dn) { if (!dn.isSubordinateOrEqualTo(baseDN)) { return false; @@ -1497,8 +1320,6 @@ return true; } /** * Determine if an entry is within the scope of the subtree * specification. @@ -1514,8 +1335,6 @@ && (refinements == null || refinements.matches(entry)); } /** * Retrieves a string representation of this subtree specification * object. @@ -1530,8 +1349,6 @@ return toString(builder).toString(); } /** * Append the string representation of the subtree specification to * the provided string builder. @@ -1542,7 +1359,6 @@ */ public StringBuilder toString(final StringBuilder builder) { boolean isFirstElement = true; // Output the optional base DN. @@ -1550,8 +1366,7 @@ if (relativeBaseDN != null && !relativeBaseDN.isRootDN()) { builder.append(" base "); StaticUtils.toRFC3641StringValue(builder, relativeBaseDN.toString()); StaticUtils.toRFC3641StringValue(builder, relativeBaseDN.toString()); isFirstElement = false; } @@ -1562,43 +1377,19 @@ if (chopBefore.iterator().hasNext() || chopAfter.iterator().hasNext()) { if (!isFirstElement) { builder.append(","); } else { isFirstElement = false; } builder.append(" specificExclusions { "); isFirstElement = append2(builder, isFirstElement, " specificExclusions { "); boolean isFirst = true; for (final DN dn : chopBefore) { if (!isFirst) { builder.append(", chopBefore:"); } else { builder.append("chopBefore:"); isFirst = false; } isFirst = append(builder, isFirst, "chopBefore:"); StaticUtils.toRFC3641StringValue(builder, dn.toString()); } for (final DN dn : chopAfter) { if (!isFirst) { builder.append(", chopAfter:"); } else { builder.append("chopAfter:"); isFirst = false; } isFirst = append(builder, isFirst, "chopAfter:"); StaticUtils.toRFC3641StringValue(builder, dn.toString()); } @@ -1608,45 +1399,21 @@ // Output the optional minimum depth. if (getMinimumDepth() > 0) { if (!isFirstElement) { builder.append(","); } else { isFirstElement = false; } builder.append(" minimum "); isFirstElement = append2(builder, isFirstElement, " minimum "); builder.append(getMinimumDepth()); } // Output the optional maximum depth. if (getMaximumDepth() >= 0) { if (!isFirstElement) { builder.append(","); } else { isFirstElement = false; } builder.append(" maximum "); isFirstElement = append2(builder, isFirstElement, " maximum "); builder.append(getMaximumDepth()); } // Output the optional refinements. if (refinements != null) { if (!isFirstElement) { builder.append(","); } else { isFirstElement = false; } builder.append(" specificationFilter "); isFirstElement = append2(builder, isFirstElement, " specificationFilter "); refinements.toString(builder); } @@ -1655,42 +1422,31 @@ return builder; } /** * Determine if the common components of this subtree specification * are equal to the common components of another subtree * specification. * * @param other * The other subtree specification. * @return Returns <code>true</code> if they are equal. */ private boolean commonComponentsEquals( final SubtreeSpecification other) private boolean append2(final StringBuilder builder, boolean isFirst, String toAppend) { if (this == other) if (isFirst) { return true; isFirst = false; } return minimumDepth == other.minimumDepth && maximumDepth == other.maximumDepth && chopBefore.values().equals(other.chopBefore.values()) && chopAfter.values().equals(other.chopAfter.values()); else { builder.append(","); } builder.append(toAppend); return isFirst; } /** * Get a hash code of the subtree specification's common components. * * @return The computed hash code. */ private int commonComponentsHashCode() private boolean append(final StringBuilder builder, boolean isFirst, String toAppend) { int hash = minimumDepth * 31 + maximumDepth; hash = hash * 31 + chopBefore.values().hashCode(); hash = hash * 31 + chopAfter.values().hashCode(); return hash; if (isFirst) { isFirst = false; } else { builder.append(", "); } builder.append(toAppend); return isFirst; } } opendj-server-legacy/src/test/java/org/opends/server/types/TestSubtreeSpecification.java
@@ -16,702 +16,107 @@ */ package org.opends.server.types; import static org.testng.AssertJUnit.assertEquals; import static org.testng.Assert.*; import org.opends.server.core.SubtreeSpecificationTestCase; import org.opends.server.types.DN; import org.opends.server.types.SubtreeSpecification; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * This class defines a set of tests for the * {@link org.opends.server.types.SubtreeSpecification} class. */ public final class TestSubtreeSpecification extends SubtreeSpecificationTestCase { /** This class defines a set of tests for the {@link SubtreeSpecification} class. */ @SuppressWarnings("javadoc") public final class TestSubtreeSpecification extends SubtreeSpecificationTestCase { /** Cached root DN. */ private DN rootDN = DN.rootDN(); /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf1() throws Exception { String input = "{}"; String output = "{ }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); @DataProvider public Object[][] valueOfData() { return new Object[][] { { "{}", "{ }" }, { " { } ", "{ }" }, { "{ base \"dc=sun, dc=com\" }", "{ base \"dc=sun,dc=com\" }" }, { "{base \"dc=sun, dc=com\"}", "{ base \"dc=sun,dc=com\" }" }, { "{ base \"dc=sun, dc=com\", " + "specificationFilter item:ds-config-rootDN }", "{ base \"dc=sun,dc=com\", " + "specificationFilter item:ds-config-rootDN }" }, { "{ base \"dc=sun, dc=com\", minimum 0 , maximum 10, " + "specificExclusions {chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\"} , specificationFilter not:not:item:foo }", "{ base \"dc=sun,dc=com\", " + "specificExclusions { chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\" }, maximum 10, specificationFilter " + "not:not:item:foo }" }, { "{ base \"\", minimum 0,maximum 10," + "specificExclusions {chopBefore:\"o=abc\"," + "chopAfter:\"o=xyz\"},specificationFilter not:not:item:foo}", "{ specificExclusions { chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\" }, " + "maximum 10, specificationFilter not:not:item:foo }" }, { "{ specificationFilter and:{item:top, item:person} }", "{ specificationFilter and:{item:top, item:person} }" }, { "{ specificationFilter or:{item:top, item:person} }", "{ specificationFilter or:{item:top, item:person} }" }, { "{ specificationFilter or:{item:top, item:foo, and:{item:one, item:two}} }", "{ specificationFilter or:{item:top, item:foo, and:{item:one, item:two}} }" }, { "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=*)\" }", "{ base \"dc=sun,dc=com\", specificationFilter \"(objectClass=*)\" }" }, }; } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf2() throws Exception { String input = " { } "; String output = "{ }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); @Test(dataProvider = "valueOfData") public void testValueOf(String specification, String expected) throws Exception { SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, specification); assertEquals(ss.toString(), expected); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf3() throws Exception { String input = "{ base \"dc=sun, dc=com\" }"; String output = "{ base \"dc=sun,dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); @DataProvider public Object[][] isWithinScopeData() { return new Object[][] { { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\" }", true }, { "dc=com", "{ base \"dc=sun, dc=com\" }", false }, { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\" }", true }, { "dc=foo, dc=bar, dc=com", "{ base \"dc=sun, dc=com\" }", false }, { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", false }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", true }, { "dc=xyz, dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", minimum 1 }", true }, { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 0 }", true }, { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 0 }", false }, { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 1 }", false }, { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", maximum 2 }", true }, { "dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"\" } }", true }, { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"\" } }", false }, { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"dc=foo\" } }", true }, { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopAfter:\"dc=foo\" } }", false }, { "dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", false }, { "dc=bar, dc=foo, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", false }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificExclusions { chopBefore:\"dc=foo\" } }", true }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter item:person }", true }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter item:organization }", false }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter not:item:person }", false }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter not:item:organization }", true }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=person)\" }", true }, { "dc=abc, dc=sun, dc=com", "{ base \"dc=sun, dc=com\", specificationFilter \"(objectClass=organization)\" }", false }, }; } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf4() throws Exception { String input = "{base \"dc=sun, dc=com\"}"; String output = "{ base \"dc=sun,dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf5() throws Exception { String input = "{ base \"dc=sun, dc=com\", " + "specificationFilter item:ds-config-rootDN }"; String output = "{ base \"dc=sun,dc=com\", " + "specificationFilter item:ds-config-rootDN }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf6() throws Exception { String input = "{ base \"dc=sun, dc=com\", minimum 0 , maximum 10, " + "specificExclusions {chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\"} , specificationFilter not:not:item:foo }"; String output = "{ base \"dc=sun,dc=com\", " + "specificExclusions { chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\" }, maximum 10, specificationFilter " + "not:not:item:foo }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf7() throws Exception { String input = "{ base \"\", minimum 0,maximum 10," + "specificExclusions {chopBefore:\"o=abc\"," + "chopAfter:\"o=xyz\"},specificationFilter not:not:item:foo}"; String output = "{ specificExclusions { chopBefore:\"o=abc\", " + "chopAfter:\"o=xyz\" }, " + "maximum 10, specificationFilter not:not:item:foo }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf8() throws Exception { String input = "{ specificationFilter and:{item:top, item:person} }"; String output = "{ specificationFilter and:{item:top, item:person} }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf9() throws Exception { String input = "{ specificationFilter or:{item:top, item:person} }"; String output = "{ specificationFilter or:{item:top, item:person} }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf10() throws Exception { String input = "{ specificationFilter " + "or:{item:top, item:foo, and:{item:one, item:two}} }"; String output = "{ specificationFilter " + "or:{item:top, item:foo, and:{item:one, item:two}} }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#valueOf(DN, String)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testValueOf11() throws Exception { String input = "{ base \"dc=sun, dc=com\", " + "specificationFilter \"(objectClass=*)\" }"; String output = "{ base \"dc=sun,dc=com\", " + "specificationFilter \"(objectClass=*)\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, input); assertEquals(output, ss.toString()); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches1() throws Exception { DN dn = DN.valueOf("dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches2() throws Exception { DN dn = DN.valueOf("dc=com"); String value = "{ base \"dc=sun, dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches3() throws Exception { DN dn = DN.valueOf("dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches4() throws Exception { DN dn = DN.valueOf("dc=foo, dc=bar, dc=com"); String value = "{ base \"dc=sun, dc=com\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches5() throws Exception { DN dn = DN.valueOf("dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", minimum 1 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches6() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", minimum 1 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches7() throws Exception { DN dn = DN.valueOf("dc=xyz, dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", minimum 1 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches8() throws Exception { DN dn = DN.valueOf("dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", maximum 0 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches9() throws Exception { DN dn = DN.valueOf("dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", maximum 0 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches10() throws Exception { DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", maximum 1 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches11() throws Exception { DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", maximum 2 }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches12() throws Exception { DN dn = DN.valueOf("dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopAfter:\"\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches13() throws Exception { DN dn = DN.valueOf("dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopAfter:\"\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches14() throws Exception { DN dn = DN.valueOf("dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopAfter:\"dc=foo\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches15() throws Exception { DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopAfter:\"dc=foo\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches16() throws Exception { DN dn = DN.valueOf("dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopBefore:\"dc=foo\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches17() throws Exception { DN dn = DN.valueOf("dc=bar, dc=foo, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopBefore:\"dc=foo\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches18() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificExclusions { chopBefore:\"dc=foo\" } }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches19() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter item:person }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches20() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter item:organization }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches21() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter not:item:person }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@link SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches22() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter not:item:organization }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@code SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches23() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter \"(objectClass=person)\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(true, ss .isWithinScope(createEntry(dn, getObjectClasses()))); } /** * Tests the {@code SubtreeSpecification#isWithinScope(Entry)} * method. * * @throws Exception * If the test failed unexpectedly. */ @Test public void testMatches24() throws Exception { DN dn = DN.valueOf("dc=abc, dc=sun, dc=com"); String value = "{ base \"dc=sun, dc=com\", " + "specificationFilter \"(objectClass=organization)\" }"; SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(false, ss .isWithinScope(createEntry(dn, getObjectClasses()))); /** Tests the {@link SubtreeSpecification#isWithinScope(Entry)} method. */ @Test(dataProvider = "isWithinScopeData") public void testIsWithinScope(String dnString, String value, boolean expected) throws Exception { DN dn = DN.valueOf(dnString); SubtreeSpecification ss = SubtreeSpecification.valueOf(rootDN, value); assertEquals(ss.isWithinScope(createEntry(dn, getObjectClasses())), expected); } }