opends/resource/config/config.ldif
@@ -2460,6 +2460,16 @@ ds-cfg-filter: (&(objectClass=groupOfUniqueNames)(objectClass=ds-virtual-static-group)) ds-cfg-allow-retrieving-membership: false dn: cn=Collective Attribute Subentries,cn=Virtual Attributes,cn=config objectClass: top objectClass: ds-cfg-virtual-attribute objectClass: ds-cfg-collective-attribute-subentries-virtual-attribute cn: Collective Attribute Subentries ds-cfg-java-class: org.opends.server.extensions.CollectiveAttributeSubentriesVirtualAttributeProvider ds-cfg-enabled: true ds-cfg-attribute-type: collectiveAttributeSubentries ds-cfg-conflict-behavior: virtual-overrides-real dn: cn=Work Queue,cn=config objectClass: top objectClass: ds-cfg-work-queue opends/resource/schema/00-core.ldif
@@ -381,6 +381,43 @@ attributeTypes: ( 1.3.6.1.4.1.7628.5.4.2 NAME 'blockInheritance' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'draft-ietf-ldup-subentry' ) attributeTypes: ( 2.5.18.6 NAME 'subtreeSpecification' SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'RFC 3672' ) attributeTypes: ( 2.5.18.12 NAME 'collectiveAttributeSubentries' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE directoryOperation NO-USER-MODIFICATION X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.18.7 NAME 'collectiveExclusions' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE directoryOperation X-ORIGIN 'RFC 3671' ) ldapSyntaxes: ( 1.3.6.1.4.1.26027.1.3.6 DESC 'Collective Conflict Behavior' X-ENUM ( 'real-overrides-virtual' 'virtual-overrides-real' 'merge-real-and-virtual' ) ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.606 NAME 'collectiveConflictBehavior' SYNTAX 1.3.6.1.4.1.26027.1.3.6 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 2.5.4.7.1 NAME 'c-l' SUP l COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.8.1 NAME 'c-st' SUP st COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.9.1 NAME 'c-street' SUP street COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.10.1 NAME 'c-o' SUP o COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.11.1 NAME 'c-ou' SUP ou COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.16.1 NAME 'c-PostalAddress' SUP postalAddress COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.17.1 NAME 'c-PostalCode' SUP postalCode COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.18.1 NAME 'c-PostOfficeBox' SUP postOfficeBox COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.19.1 NAME 'c-PhysicalDeliveryOfficeName' SUP physicalDeliveryOfficeName COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.20.1 NAME 'c-TelephoneNumber' SUP telephoneNumber COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.21.1 NAME 'c-TelexNumber' SUP telexNumber COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.23.1 NAME 'c-FacsimileTelephoneNumber' SUP facsimileTelephoneNumber COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.5.4.25.1 NAME 'c-InternationalISDNNumber' SUP internationalISDNNumber COLLECTIVE X-ORIGIN 'RFC 3671' ) attributeTypes: ( 2.16.840.1.113730.3.1.55 NAME 'aci' DESC 'Sun-defined access control information attribute type' EQUALITY octetStringMatch @@ -613,6 +650,12 @@ DESC 'Inheritable LDAP Subentry class, version 1' SUP ldapSubEntry STRUCTURAL MUST ( inheritable ) MAY ( blockInheritance ) X-ORIGIN 'draft-ietf-ldup-subentry' ) objectClasses: ( 2.5.17.0 NAME 'subentry' DESC 'LDAP Subentry class' SUP top STRUCTURAL MUST ( cn $ subtreeSpecification ) X-ORIGIN 'RFC 3672' ) objectClasses: ( 2.5.17.2 NAME 'collectiveAttributeSubentry' DESC 'LDAP Collective Attributes Subentry class' AUXILIARY X-ORIGIN 'RFC 3671' ) objectClasses: ( 2.16.840.1.113730.3.2.33 NAME 'groupOfURLs' DESC 'Sun-defined objectclass' SUP top STRUCTURAL MUST ( cn ) MAY ( memberURL $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) opends/resource/schema/02-config.ldif
@@ -4151,4 +4151,9 @@ ds-cfg-enabled ) MAY ( ds-cfg-ecl-include ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.235 NAME 'ds-cfg-collective-attribute-subentries-virtual-attribute' SUP ds-cfg-virtual-attribute STRUCTURAL X-ORIGIN 'OpenDS Directory Server' ) opends/src/admin/defn/org/opends/server/admin/std/CollectiveAttributeSubentriesVirtualAttributeConfiguration.xml
New file @@ -0,0 +1,70 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- ! 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 ! ! ! Copyright 2009 Sun Microsystems, Inc. ! --> <adm:managed-object name="collective-attribute-subentries-virtual-attribute" plural-name="collective-attribute-subentries-virtual-attributes" package="org.opends.server.admin.std" extends="virtual-attribute" xmlns:adm="http://www.opends.org/admin" xmlns:ldap="http://www.opends.org/admin-ldap"> <adm:synopsis> The <adm:user-friendly-name /> generates a virtual attribute that specifies all collective attribute subentries that affect the entry. </adm:synopsis> <adm:profile name="ldap"> <ldap:object-class> <ldap:name> ds-cfg-collective-attribute-subentries-virtual-attribute </ldap:name> <ldap:superior>ds-cfg-virtual-attribute</ldap:superior> </ldap:object-class> </adm:profile> <adm:property-override name="java-class" advanced="true"> <adm:default-behavior> <adm:defined> <adm:value> org.opends.server.extensions.CollectiveAttributeSubentriesVirtualAttributeProvider </adm:value> </adm:defined> </adm:default-behavior> </adm:property-override> <adm:property-override name="conflict-behavior" advanced="true"> <adm:default-behavior> <adm:defined> <adm:value>virtual-overrides-real</adm:value> </adm:defined> </adm:default-behavior> </adm:property-override> <adm:property-override name="attribute-type"> <adm:default-behavior> <adm:defined> <adm:value>collectiveAttributeSubentries</adm:value> </adm:defined> </adm:default-behavior> </adm:property-override> </adm:managed-object> opends/src/messages/messages/core.properties
@@ -1825,3 +1825,6 @@ 60 seconds. This option cannot be used with the -N, --nodetach option FATAL_ERR_DSCORE_ERROR_NODETACH_TIMEOUT_723=In no-detach mode, the 'timeout' \ option cannot be used SEVERE_WARN_SUBENTRY_FILTER_NOT_INDEXED_724=The search filter "%s" used by \ subentry manager is not indexed in backend %s. Backend initialization \ for subentry manager processing might take a very long time to complete opends/src/messages/messages/extension.properties
@@ -1422,3 +1422,6 @@ INFO_GSSAPI_STARTED_574=The GSSAPI SASL mechanism handler initialization \ was successful INFO_GSSAPI_STOPPED_575=The GSSAPI SASL mechanism handler has been stopped MILD_ERR_COLLECTIVEATTRIBUTESUBENTRIES_VATTR_NOT_SEARCHABLE_576=The %s \ attribute is not searchable and should not be included in otherwise \ unindexed search filters opends/src/messages/messages/schema.properties
@@ -881,9 +881,6 @@ SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \ for attribute type %s is invalid because its attribute usage %s is not the \ same as the usage for its superior type %s SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE_269=The \ definition for attribute type %s is invalid because it is defined as a \ collective type but the superior type %s is not collective SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \ definition for attribute type %s is invalid because it is not defined as a \ collective type but the superior type %s is collective @@ -893,9 +890,6 @@ MILD_ERR_ATTR_SYNTAX_DCR_PROHIBITED_REQUIRED_BY_AUXILIARY_272=The DIT content \ rule "%s" is not valid because it prohibits the use of attribute type %s \ which is required by the associated auxiliary object class %s SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL_273=The definition \ for attribute type %s is invalid because it is declared COLLECTIVE but does \ not have a usage of userApplications SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NO_USER_MOD_NOT_OPERATIONAL_274=The \ definition for attribute type %s is invalid because it is declared \ NO-USER-MODIFICATION but does not have an operational usage opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -594,6 +594,9 @@ // The group manager for the Directory Server. private GroupManager groupManager; // The subentry manager for the Directory Server. private SubentryManager subentryManager; // The configuration manager for identity mappers. private IdentityMapperConfigManager identityMapperConfigManager; @@ -1420,6 +1423,13 @@ rootDNConfigManager.initializeRootDNs(); // Initialize the subentry manager. subentryManager = new SubentryManager(); // The configuration backend has already been registered at this point // so we need to handle it explicitly. subentryManager.performBackendInitializationProcessing(configHandler); // Initialize the group manager. initializeGroupManager(); @@ -2671,6 +2681,18 @@ /** * Retrieves the Directory Server subentry manager. * * @return The Directory Server subentry manager. */ public static SubentryManager getSubentryManager() { return directoryServer.subentryManager; } /** * Initializes the set of supported controls for the Directory Server. * * @throws ConfigException If there is a configuration problem with the opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -609,7 +609,7 @@ // Determine whether the provided entry is a subentry and if so whether it // should be returned. if (entry.isLDAPSubentry()) if (entry.isSubentry() || entry.isLDAPSubentry()) { if ((getScope() != SearchScope.BASE_OBJECT) && (! isReturnLDAPSubentries())) @@ -1494,7 +1494,11 @@ if (filter.getAttributeType().isObjectClassType()) { AttributeValue v = filter.getAssertionValue(); if (toLowerCase(v.getValue().toString()).equals("ldapsubentry")) // FIXME : technically this is not correct since the presense // of draft oc would trigger rfc oc visibility and visa versa. String stringValueLC = toLowerCase(v.getValue().toString()); if (stringValueLC.equals(OC_LDAP_SUBENTRY_LC) || stringValueLC.equals(OC_SUBENTRY)) { setReturnLDAPSubentries(true); } opends/src/server/org/opends/server/core/SubentryManager.java
New file @@ -0,0 +1,647 @@ /* * 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 * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.core; import java.util.*; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.opends.server.api.Backend; import org.opends.server.api.BackendInitializationListener; import org.opends.server.api.ChangeNotificationListener; import org.opends.server.controls.SubentriesControl; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.types.Control; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DereferencePolicy; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SearchScope; import org.opends.server.types.SearchFilter; import org.opends.server.types.SubEntry; import org.opends.server.types.operation.PostResponseAddOperation; import org.opends.server.types.operation.PostResponseDeleteOperation; import org.opends.server.types.operation.PostResponseModifyOperation; import org.opends.server.types.operation.PostResponseModifyDNOperation; import org.opends.server.workflowelement.localbackend. LocalBackendSearchOperation; import static org.opends.messages.CoreMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.loggers.ErrorLogger.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.config.ConfigConstants.*; /** * This class provides a mechanism for interacting with subentries defined in * the Directory Server. It will handle all necessary processing at server * startup to identify and load subentries within the server. * <BR><BR> * FIXME: At the present time, it assumes that all of the necessary * information about subentries defined in the server can be held in * memory. If it is determined that this approach is not workable * in all cases, then we will need an alternate strategy. */ public class SubentryManager implements BackendInitializationListener, ChangeNotificationListener { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); // A mapping between the DNs and applicable subentries. private HashMap<DN,List<SubEntry>> dn2SubEntry; // A mapping between the DNs and applicable collective subentries. private HashMap<DN,List<SubEntry>> dn2CollectiveSubEntry; // Internal search all operational attributes. private LinkedHashSet<String> requestAttrs; // Lock to protect internal data structures. private final ReentrantReadWriteLock lock; /** * Creates a new instance of this group manager. */ public SubentryManager() { lock = new ReentrantReadWriteLock(); dn2SubEntry = new HashMap<DN,List<SubEntry>>(); dn2CollectiveSubEntry = new HashMap<DN,List<SubEntry>>(); requestAttrs = new LinkedHashSet<String>(); requestAttrs.add("subtreespecification"); requestAttrs.add("*"); DirectoryServer.registerBackendInitializationListener(this); DirectoryServer.registerChangeNotificationListener(this); } /** * Add a given entry to this subentry manager. * @param entry to add. */ private void addSubEntry(Entry entry) throws DirectoryException { SubEntry subEntry = new SubEntry(entry); RFC3672SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); DN subDN = subSpec.getBaseDN(); List<SubEntry> subList = null; lock.writeLock().lock(); try { if (subEntry.isCollective()) { subList = dn2CollectiveSubEntry.get(subDN); } else { subList = dn2SubEntry.get(subDN); } if (subList == null) { subList = new ArrayList<SubEntry>(); if (subEntry.isCollective()) { dn2CollectiveSubEntry.put(subDN, subList); } else { dn2SubEntry.put(subDN, subList); } } subList.add(subEntry); } finally { lock.writeLock().unlock(); } } /** * Remove a given entry from this subentry manager. * @param entry to remove. */ private void removeSubEntry(Entry entry) { lock.writeLock().lock(); try { boolean removed = false; Iterator<Map.Entry<DN, List<SubEntry>>> iterator = dn2SubEntry.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = iterator.next(); List<SubEntry> subList = mapEntry.getValue(); for (SubEntry subEntry : subList) { if (subEntry.getDN().equals(entry.getDN())) { removed = subList.remove(subEntry); break; } } if (subList.isEmpty()) { iterator.remove(); } if (removed) { return; } } iterator = dn2CollectiveSubEntry.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = iterator.next(); List<SubEntry> subList = mapEntry.getValue(); for (SubEntry subEntry : subList) { if (subEntry.getDN().equals(entry.getDN())) { removed = subList.remove(subEntry); break; } } if (subList.isEmpty()) { iterator.remove(); } if (removed) { return; } } } finally { lock.writeLock().unlock(); } } /** * {@inheritDoc} In this case, the server will search the backend to find * all subentries that it may contain and register them with this manager. */ public void performBackendInitializationProcessing(Backend backend) { InternalClientConnection conn = InternalClientConnection.getRootConnection(); LinkedList<Control> requestControls = new LinkedList<Control>(); requestControls.add(new SubentriesControl(true, true)); SearchFilter filter = null; try { filter = SearchFilter.createFilterFromString("(" + ATTR_OBJECTCLASS + "=" + OC_SUBENTRY + ")"); if (backend.getEntryCount() > 0 && ! backend.isIndexed(filter)) { logError(WARN_SUBENTRY_FILTER_NOT_INDEXED.get( String.valueOf(filter), backend.getBackendID())); } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } for (DN baseDN : backend.getBaseDNs()) { try { if (! backend.entryExists(baseDN)) { continue; } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Is there anything that we need to do here? continue; } InternalSearchOperation internalSearch = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), requestControls, baseDN, SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, filter, requestAttrs, null); LocalBackendSearchOperation localSearch = new LocalBackendSearchOperation(internalSearch); try { backend.search(localSearch); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Is there anything that we need to do here? continue; } for (SearchResultEntry entry : internalSearch.getSearchEntries()) { if (entry.isSubentry()) { try { addSubEntry(entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Handle this. continue; } } } } } /** * 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. * @return applicable subentries. */ public List<SubEntry> getSubentries(DN dn) { if (dn2SubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<SubEntry>(); lock.readLock().lock(); try { for (DN subDN = dn; subDN != null; subDN = subDN.getParent()) { List<SubEntry> subList = dn2SubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { RFC3672SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isDNWithinScope(dn)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; } /** * Return subentries applicable to specific entry. * Note that this getter will skip any collective subentries, * returning only applicable regular subentries. * @param entry for which to retrieve applicable * subentries. * @return applicable subentries. */ public List<SubEntry> getSubentries(Entry entry) { if (dn2SubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<SubEntry>(); lock.readLock().lock(); try { for (DN subDN = entry.getDN(); subDN != null; subDN = subDN.getParent()) { List<SubEntry> subList = dn2SubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { RFC3672SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isWithinScope(entry)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; } /** * Return collective subentries applicable to specific DN. * Note that this getter will skip any regular subentries, * returning only applicable collective subentries. * @param dn for which to retrieve applicable * subentries. * @return applicable subentries. */ public List<SubEntry> getCollectiveSubentries(DN dn) { if (dn2CollectiveSubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<SubEntry>(); lock.readLock().lock(); try { for (DN subDN = dn; subDN != null; subDN = subDN.getParent()) { List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { RFC3672SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isDNWithinScope(dn)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; } /** * Return collective subentries applicable to specific entry. * Note that this getter will skip any regular subentries, * returning only applicable collective subentries. * @param entry for which to retrieve applicable * subentries. * @return applicable subentries. */ public List<SubEntry> getCollectiveSubentries(Entry entry) { if (dn2CollectiveSubEntry.isEmpty()) { return Collections.emptyList(); } List<SubEntry> subentries = new ArrayList<SubEntry>(); lock.readLock().lock(); try { for (DN subDN = entry.getDN(); subDN != null; subDN = subDN.getParent()) { List<SubEntry> subList = dn2CollectiveSubEntry.get(subDN); if (subList != null) { for (SubEntry subEntry : subList) { RFC3672SubtreeSpecification subSpec = subEntry.getSubTreeSpecification(); if (subSpec.isWithinScope(entry)) { subentries.add(subEntry); } } } } } finally { lock.readLock().unlock(); } return subentries; } /** * {@inheritDoc} In this case, the server will de-register * all subentries associated with the provided backend. */ public void performBackendFinalizationProcessing(Backend backend) { lock.writeLock().lock(); try { Iterator<Map.Entry<DN, List<SubEntry>>> iterator = dn2SubEntry.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = iterator.next(); List<SubEntry> subList = mapEntry.getValue(); for (SubEntry subEntry : subList) { if (backend.handlesEntry(subEntry.getDN())) { subList.remove(subEntry); } } if (subList.isEmpty()) { iterator.remove(); } } iterator = dn2CollectiveSubEntry.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<DN, List<SubEntry>> mapEntry = iterator.next(); List<SubEntry> subList = mapEntry.getValue(); for (SubEntry subEntry : subList) { if (backend.handlesEntry(subEntry.getDN())) { subList.remove(subEntry); } } if (subList.isEmpty()) { iterator.remove(); } } } finally { lock.writeLock().unlock(); } } /** * {@inheritDoc} In this case, each entry is checked to see if it is * a subentry, and if so it will be registered with this manager. */ public void handleAddOperation(PostResponseAddOperation addOperation, Entry entry) { if (entry.isSubentry()) { try { addSubEntry(entry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Handle this. } } } /** * {@inheritDoc} In this case, each entry is checked to see if it is * a subentry, and if so it will be deregistered with this manager. */ public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation, Entry entry) { if (entry.isSubentry()) { removeSubEntry(entry); } } /** * {@inheritDoc} In this case, if the entry is a registered subentry * then it will be recreated from the contents of the provided entry * and re-registered with this manager. */ public void handleModifyOperation(PostResponseModifyOperation modifyOperation, Entry oldEntry, Entry newEntry) { if (oldEntry.isSubentry()) { removeSubEntry(oldEntry); } if (newEntry.isSubentry()) { try { addSubEntry(newEntry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Handle this. } } } /** * {@inheritDoc} In this case, if the subentry is registered then it * will be recreated from the contents of the provided entry and re- * registered with this manager under the new DN and the old instance * will be deregistered. */ public void handleModifyDNOperation( PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry, Entry newEntry) { if (oldEntry.isSubentry()) { removeSubEntry(oldEntry); try { addSubEntry(newEntry); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } // FIXME -- Handle this. } } } } opends/src/server/org/opends/server/extensions/CollectiveAttributeSubentriesVirtualAttributeProvider.java
New file @@ -0,0 +1,153 @@ /* * 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 * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.extensions; import java.util.HashSet; import java.util.List; import java.util.Set; import org.opends.messages.Message; import org.opends.server.admin.std.server. CollectiveAttributeSubentriesVirtualAttributeCfg; import org.opends.server.api.VirtualAttributeProvider; import org.opends.server.core.DirectoryServer; import org.opends.server.core.SearchOperation; import org.opends.server.config.ConfigException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.loggers.debug.DebugLogger.getTracer; /** * This class implements a virtual attribute provider to serve the * collectiveAttributeSubentries operational attribute as described * in RFC 3671. */ public class CollectiveAttributeSubentriesVirtualAttributeProvider extends VirtualAttributeProvider< CollectiveAttributeSubentriesVirtualAttributeCfg> { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** * Creates a new instance of this HasSubordinates virtual attribute provider. */ public CollectiveAttributeSubentriesVirtualAttributeProvider() { super(); // All initialization should be performed in the // initializeVirtualAttributeProvider method. } /** * {@inheritDoc} */ @Override() public void initializeVirtualAttributeProvider( CollectiveAttributeSubentriesVirtualAttributeCfg configuration) throws ConfigException, InitializationException { // No initialization is required. } /** * {@inheritDoc} */ @Override() public boolean isMultiValued() { return true; } /** * {@inheritDoc} */ @Override() public Set<AttributeValue> getValues(Entry entry, VirtualAttributeRule rule) { Set<AttributeValue> valueSet = new HashSet<AttributeValue>(); List<SubEntry> subentries = DirectoryServer.getSubentryManager().getCollectiveSubentries(entry); AttributeType dnAttrType = DirectoryServer.getAttributeType("2.5.4.49"); for (SubEntry subentry : subentries) { if (subentry.isCollective()) { DN subentryDN = subentry.getDN(); AttributeValue value = AttributeValues.create( dnAttrType, subentryDN.toString()); valueSet.add(value); } } return valueSet; } /** * {@inheritDoc} */ @Override() public boolean isSearchable(VirtualAttributeRule rule, SearchOperation searchOperation) { return false; } /** * {@inheritDoc} */ @Override() public void processSearch(VirtualAttributeRule rule, SearchOperation searchOperation) { searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); Message message = ERR_COLLECTIVEATTRIBUTESUBENTRIES_VATTR_NOT_SEARCHABLE.get( rule.getAttributeType().getNameOrOID()); searchOperation.appendErrorMessage(message); } } opends/src/server/org/opends/server/schema/AttributeTypeSyntax.java
@@ -983,32 +983,17 @@ throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } if (superiorType.isCollective() != isCollective) if (superiorType.isCollective()) { Message message; if (isCollective) { message = WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_FROM_NONCOLLECTIVE.get( oid, superiorType.getNameOrOID()); } else { message = WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE.get( oid, superiorType.getNameOrOID()); } throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } } // If the attribute type is COLLECTIVE, then it must have a usage of // userApplications. if (isCollective && (attributeUsage != AttributeUsage.USER_APPLICATIONS)) if (!isCollective) { Message message = WARN_ATTR_SYNTAX_ATTRTYPE_COLLECTIVE_IS_OPERATIONAL.get(oid); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE.get( oid, superiorType.getNameOrOID()); throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message); } } } opends/src/server/org/opends/server/types/CollectiveVirtualAttribute.java
New file @@ -0,0 +1,131 @@ /* * 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 * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.types; import java.util.Iterator; import java.util.List; import java.util.Set; /** * This class defines a collective virtual attribute, which is a * special kind of attribute whose values do not actually exist * in persistent storage but rather are obtained dynamically * from applicable collective attribute subentry. */ public class CollectiveVirtualAttribute extends AbstractAttribute { // The attribute this collective virtual attribute is based on. private Attribute attribute; /** * Creates a new collective virtual attribute. * @param attribute The attribute this collective * virtual attribute is based on. */ public CollectiveVirtualAttribute(Attribute attribute) { this.attribute = attribute; } /** * {@inheritDoc} */ public ConditionResult approximatelyEqualTo(AttributeValue value) { return attribute.approximatelyEqualTo(value); } /** * {@inheritDoc} */ public boolean contains(AttributeValue value) { return attribute.contains(value); } /** * {@inheritDoc} */ public AttributeType getAttributeType() { return attribute.getAttributeType(); } /** * {@inheritDoc} */ public Set<String> getOptions() { return attribute.getOptions(); } /** * {@inheritDoc} */ public ConditionResult greaterThanOrEqualTo(AttributeValue value) { return attribute.greaterThanOrEqualTo(value); } /** * {@inheritDoc} */ public boolean isVirtual() { return true; } /** * {@inheritDoc} */ public Iterator<AttributeValue> iterator() { return attribute.iterator(); } /** * {@inheritDoc} */ public ConditionResult lessThanOrEqualTo(AttributeValue value) { return attribute.lessThanOrEqualTo(value); } /** * {@inheritDoc} */ public ConditionResult matchesSubstring(ByteString subInitial, List<ByteString> subAny, ByteString subFinal) { return attribute.matchesSubstring(subInitial, subAny, subFinal); } /** * {@inheritDoc} */ public int size() { return attribute.size(); } /** * {@inheritDoc} */ public void toString(StringBuilder buffer) { attribute.toString(buffer); } } opends/src/server/org/opends/server/types/Entry.java
@@ -1763,7 +1763,10 @@ { if (a.optionsEqual(options)) { return a.contains(value); if (a.contains(value)) { return true; } } } @@ -3304,6 +3307,92 @@ /** * Indicates whether this entry meets the criteria to consider it * an RFC 3672 LDAP subentry (i.e., it contains the "subentry" * objectclass). * * @return <CODE>true</CODE> if this entry meets the criteria to * consider it an RFC 3672 LDAP subentry, or <CODE>false * </CODE> if not. */ public boolean isSubentry() { ObjectClass subentryOC = DirectoryServer.getObjectClass(OC_SUBENTRY); if (subentryOC == null) { // This should not happen -- The server doesn't // have a subentry objectclass defined. if (debugEnabled()) { TRACER.debugWarning( "No %s objectclass is defined in the server schema.", OC_SUBENTRY); } for (String ocName : objectClasses.values()) { if (ocName.equalsIgnoreCase(OC_SUBENTRY)) { return true; } } return false; } // Make the determination based on whether this // entry has the subentry objectclass. return objectClasses.containsKey(subentryOC); } /** * Indicates whether the entry meets the criteria to consider it an * RFC 3671 LDAP collective attributes subentry (i.e., it contains * the "collectiveAttributeSubentry" objectclass). * * @return <CODE>true</CODE> if this entry meets the criteria to * consider it an RFC 3671 LDAP collective attributes * subentry, or <CODE>false</CODE> if not. */ public boolean isCollectiveAttributeSubentry() { ObjectClass collectiveAttributeSubentryOC = DirectoryServer.getObjectClass(OC_COLLECTIVE_ATTR_SUBENTRY); if (collectiveAttributeSubentryOC == null) { // This should not happen -- The server doesn't have // a collectiveAttributeSubentry objectclass defined. if (debugEnabled()) { TRACER.debugWarning( "No %s objectclass is defined in the server schema.", OC_COLLECTIVE_ATTR_SUBENTRY); } for (String ocName : objectClasses.values()) { if (ocName.equalsIgnoreCase(OC_COLLECTIVE_ATTR_SUBENTRY)) { return true; } } return false; } // Make the determination based on whether this entry // has the collectiveAttributeSubentry objectclass. return objectClasses.containsKey(collectiveAttributeSubentryOC); } /** * Indicates whether this entry falls within the range of the * provided search base DN and scope. * @@ -3322,12 +3411,185 @@ /** * Performs any necessary collective attribute processing for this * entry. This should only be called at the time the entry is * decoded or created within the backend. */ private void processCollectiveAttributes() { if (this.isSubentry() || this.isLDAPSubentry()) { return; } // Get applicable collective subentries. List<SubEntry> collectiveAttrSubentries = DirectoryServer.getSubentryManager( ).getCollectiveSubentries(this); if ((collectiveAttrSubentries == null) || collectiveAttrSubentries.isEmpty()) { // Nothing to see here, move along. return; } // Get collective attribute exclusions. AttributeType exclusionsType = DirectoryServer.getAttributeType( ATTR_COLLECTIVE_EXCLUSIONS_LC); List<Attribute> exclusionsAttrList = operationalAttributes.get(exclusionsType); Set<String> exclusionsNameSet = new HashSet<String>(); if ((exclusionsAttrList != null) && !exclusionsAttrList.isEmpty()) { for (Attribute attr : exclusionsAttrList) { for (AttributeValue attrValue : attr) { String exclusionsName = attrValue.toString().toLowerCase(); if (exclusionsName.equals( VALUE_COLLECTIVE_EXCLUSIONS_EXCLUDE_ALL_LC) || exclusionsName.equals( OID_COLLECTIVE_EXCLUSIONS_EXCLUDE_ALL)) { return; } exclusionsNameSet.add(exclusionsName); } } } // Process collective attributes. for (SubEntry subEntry : collectiveAttrSubentries) { if (subEntry.isCollective()) { List<Attribute> collectiveAttrList = subEntry.getCollectiveAttributes(); for (Attribute collectiveAttr : collectiveAttrList) { AttributeType attributeType = collectiveAttr.getAttributeType(); if (exclusionsNameSet.contains( attributeType.getNormalizedPrimaryNameOrOID())) { continue; } List<Attribute> attrList = userAttributes.get(attributeType); if ((attrList == null) || attrList.isEmpty()) { attrList = operationalAttributes.get(attributeType); if ((attrList == null) || attrList.isEmpty()) { // There aren't any conflicts, so we can just add the // attribute to the entry. attrList = new LinkedList<Attribute>(); attrList.add(collectiveAttr); if (attributeType.isOperational()) { operationalAttributes.put(attributeType, attrList); } else { userAttributes.put(attributeType, attrList); } } else { // There is a conflict with an existing operational // attribute. if (attrList.get(0).isVirtual()) { // The existing attribute is already virtual, // so we've got a different conflict, but // we'll let the first win. // FIXME -- Should we handle this differently? continue; } // The conflict is with a real attribute. See what the // conflict behavior is and figure out how to handle it. switch (subEntry.getConflictBehavior()) { case REAL_OVERRIDES_VIRTUAL: // We don't need to update the entry because // the real attribute will take precedence. break; case VIRTUAL_OVERRIDES_REAL: // We need to move the real attribute to the // suppressed list and replace it with the // virtual attribute. suppressedAttributes.put(attributeType, attrList); attrList = new LinkedList<Attribute>(); attrList.add(collectiveAttr); operationalAttributes.put(attributeType, attrList); break; case MERGE_REAL_AND_VIRTUAL: // We need to add the virtual attribute to the // list and keep the existing real attribute(s). attrList.add(collectiveAttr); break; } } } else { // There is a conflict with an existing user attribute. if (attrList.get(0).isVirtual()) { // The existing attribute is already virtual, // so we've got a different conflict, but // we'll let the first win. // FIXME -- Should we handle this differently? continue; } // The conflict is with a real attribute. See what the // conflict behavior is and figure out how to handle it. switch (subEntry.getConflictBehavior()) { case REAL_OVERRIDES_VIRTUAL: // We don't need to update the entry because the real // attribute will take precedence. break; case VIRTUAL_OVERRIDES_REAL: // We need to move the real attribute to the // suppressed list and replace it with the // virtual attribute. suppressedAttributes.put(attributeType, attrList); attrList = new LinkedList<Attribute>(); attrList.add(collectiveAttr); userAttributes.put(attributeType, attrList); break; case MERGE_REAL_AND_VIRTUAL: // We need to add the virtual attribute to the // list and keep the existing real attribute(s). attrList.add(collectiveAttr); break; } } } } } } /** * Performs any necessary virtual attribute processing for this * entry. This should only be called at the time the entry is * decoded or created within the backend. */ public void processVirtualAttributes() { // Collective attributes. processCollectiveAttributes(); // Virtual attributes. for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes(this)) { opends/src/server/org/opends/server/types/SubEntry.java
New file @@ -0,0 +1,281 @@ /* * 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 * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.types; import java.util.List; import java.util.ArrayList; import java.util.Set; import java.util.LinkedHashSet; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.core.DirectoryServer; import org.opends.server.core.RFC3672SubtreeSpecification; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; /** * This class represents RFC 3672 subentries and RFC 3671 * collective attribute subentries objects. */ public class SubEntry { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** * Defines the set of permissable values for the conflict behavior. * Specifies the behavior that the server is to exhibit for entries * that already contain one or more real values for the associated * collective attribute. */ public static enum CollectiveConflictBehavior { /** * Indicates that the virtual attribute provider is to preserve * any real values contained in the entry and merge them with the * set of generated virtual values so that both the real and * virtual values are used. */ MERGE_REAL_AND_VIRTUAL("merge-real-and-virtual"), /** * Indicates that any real values contained in the entry are * preserved and used, and virtual values are not generated. */ REAL_OVERRIDES_VIRTUAL("real-overrides-virtual"), /** * Indicates that the virtual attribute provider suppresses any * real values contained in the entry and generates virtual values * and uses them. */ VIRTUAL_OVERRIDES_REAL("virtual-overrides-real"); // String representation of the value. private final String name; /** * Private constructor. * @param name for this conflict behavior. */ private CollectiveConflictBehavior(String name) { this.name = name; } /** * {@inheritDoc} */ @Override public String toString() { return name; } } /** * The name of the "collectiveConflictBehavior" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_COLLECTIVE_CONFLICT_BEHAVIOR = "collectiveconflictbehavior"; // Attribute option to mark attributes collective. private static final String ATTR_OPTION_COLLECTIVE = "collective"; // Entry object. private Entry entry; // Subtree specification. private RFC3672SubtreeSpecification subTreeSpec; // Collective subentry flag. private boolean isCollective = false; // Collective attributes. private List<Attribute> collectiveAttributes; // Conflict behavior. private CollectiveConflictBehavior conflictBehavior = CollectiveConflictBehavior.REAL_OVERRIDES_VIRTUAL; /** * Constructs a subentry object from a given entry object. * @param entry LDAP subentry to construct from. * @throws DirectoryException if there is a problem with * constructing a subentry from a given entry. */ public SubEntry(Entry entry) throws DirectoryException { // Entry object. this.entry = entry; // Process subtree specification. this.subTreeSpec = null; AttributeType specAttrType = DirectoryServer.getAttributeType( ATTR_SUBTREE_SPEC_LC, true); List<Attribute> specAttrList = entry.getAttribute(specAttrType); for (Attribute attr : specAttrList) { for (AttributeValue value : attr) { this.subTreeSpec = RFC3672SubtreeSpecification.valueOf( entry.getDN().getParent(), value.toString()); break; } if (this.subTreeSpec != null) { break; } } // Subentry has to to have a subtree specification. if (this.subTreeSpec == null) { // There is none for some reason so create a dummy. this.subTreeSpec = new RFC3672SubtreeSpecification( entry.getDN().getParent(), null, -1, -1, null, null, null); } // Determine if this subentry is collective attribute subentry. this.isCollective = entry.isCollectiveAttributeSubentry(); // Process collective attributes. this.collectiveAttributes = new ArrayList<Attribute>(); if (this.isCollective) { List<Attribute> subAttrList = entry.getAttributes(); for (Attribute subAttr : subAttrList) { AttributeType attrType = subAttr.getAttributeType(); if (attrType.isCollective()) { CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(subAttr); this.collectiveAttributes.add(collectiveAttr); } else if (subAttr.hasOption(ATTR_OPTION_COLLECTIVE)) { AttributeBuilder builder = new AttributeBuilder( subAttr.getAttributeType()); builder.addAll(subAttr); Set<String> options = new LinkedHashSet<String>( subAttr.getOptions()); options.remove(ATTR_OPTION_COLLECTIVE); builder.setOptions(options); Attribute attr = builder.toAttribute(); CollectiveVirtualAttribute collectiveAttr = new CollectiveVirtualAttribute(attr); this.collectiveAttributes.add(collectiveAttr); } } // Conflict behavior. List<Attribute> attrList = entry.getAttribute( ATTR_COLLECTIVE_CONFLICT_BEHAVIOR); if ((attrList != null) && !attrList.isEmpty()) { for (Attribute attr : attrList) { for (AttributeValue value : attr) { for (CollectiveConflictBehavior behavior : CollectiveConflictBehavior.values()) { if (behavior.toString().equals(value.toString())) { this.conflictBehavior = behavior; break; } } } } } } } /** * Retrieves the distinguished name for this subentry. * @return The distinguished name for this subentry. */ public DN getDN() { return this.entry.getDN(); } /** * Getter to retrieve the actual entry object * for this subentry. * @return entry object for this subentry. */ public Entry getEntry() { return this.entry; } /** * Indicates whether or not this subentry is * a collective attribute subentry. * @return <code>true</code> if collective, * <code>false</code> otherwise. */ public boolean isCollective() { return this.isCollective; } /** * Getter for subentry subtree specification. * @return subtree specification for this subentry. */ public RFC3672SubtreeSpecification getSubTreeSpecification() { return this.subTreeSpec; } /** * Getter for collective attributes contained within this subentry. * @return collective attributes contained within this subentry. */ public List<Attribute> getCollectiveAttributes() { return this.collectiveAttributes; } /** * 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; } } opends/src/server/org/opends/server/util/ServerConstants.java
@@ -224,6 +224,69 @@ /** * The name of the standard "subtreeSpecification" attribute type, * formatted in camel case. */ public static final String ATTR_SUBTREE_SPEC = "subtreeSpecification"; /** * The name of the standard "subtreeSpecification" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_SUBTREE_SPEC_LC = "subtreespecification"; /** * The name of the standard "collectiveExclusions" attribute type, * formatted in camel case. */ public static final String ATTR_COLLECTIVE_EXCLUSIONS = "collectiveExclusions"; /** * The name of the standard "collectiveExclusions" attribute type, * formatted in all lowercase characters. */ public static final String ATTR_COLLECTIVE_EXCLUSIONS_LC = "collectiveexclusions"; /** * The value of the standard "excludeAllCollectiveAttributes" attribute * value of the standard "collectiveExclusions" attribute type, * formatted in camel case. */ public static final String VALUE_COLLECTIVE_EXCLUSIONS_EXCLUDE_ALL = "excludeAllCollectiveAttributes"; /** * The value of the standard "excludeAllCollectiveAttributes" attribute * value of the standard "collectiveExclusions" attribute type, * formatted in all lowercase characters. */ public static final String VALUE_COLLECTIVE_EXCLUSIONS_EXCLUDE_ALL_LC = "excludeallcollectiveattributes"; /** * The OID of the standard "excludeAllCollectiveAttributes" attribute * value of the standard "collectiveExclusions" attribute type. */ public static final String OID_COLLECTIVE_EXCLUSIONS_EXCLUDE_ALL = "2.5.18.0"; /** * The name of the monitor attribute that is used to hold a backend ID. */ public static final String ATTR_MONITOR_BACKEND_ID = "ds-backend-id"; @@ -837,6 +900,35 @@ /** * The name of the RFC 3672 "subentry" objectclass (which is a special * type of objectclass that makes a kind of "operational" entry), * formatted in all lowercase. */ public static final String OC_SUBENTRY = "subentry"; /** * The name of the RFC 3671 "collectiveAttributeSubentry" objectclass * (which is a special type of objectclass that makes a kind of shared * attributes subentry), formatted in camel case. */ public static final String OC_COLLECTIVE_ATTR_SUBENTRY = "collectiveAttributeSubentry"; /** * The name of the RFC 3671 "collectiveAttributeSubentry" objectclass * (which is a special type of objectclass that makes a kind of shared * attributes subentry), formatted in all lowercase. */ public static final String OC_COLLECTIVE_ATTR_SUBENTRY_LC = "collectiveattributesubentry"; /** * The name of the custom objectclass that will be included in backend monitor * entries. */ opends/tests/unit-tests-testng/src/server/org/opends/server/schema/AttributeTypeSyntaxTest.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.schema; @@ -81,13 +81,13 @@ " SUBSTR caseIgnoreSubstringsMatch" + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE" + " COLLECTIVE USAGE userApplications )", false}, // Collective can't inherit from non-collective true}, // Collective can inherit from non-collective {"(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE " + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch" + " SUBSTR caseIgnoreSubstringsMatch" + " SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE" + " COLLECTIVE USAGE directoryOperation )", false}, // Collective can't be operational true}, // Collective can be operational {"(1.2.8.5 NAME 'testtype' DESC 'full type' OBSOLETE SUP cn " + " EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch" + " SUBSTR caseIgnoreSubstringsMatch" +