Fixes issues #4552 #4557, making sure plugins and internal services are properly handling subtree move or delete.
The changes particularly resolve problems raised by the community with the referential integrity and the isMemberOf plug-ins.
Unit-tests have been updated to cover those cases
2 files added
42 files modified
| | |
| | | ds-cfg-plugin-type: postOperationDelete |
| | | ds-cfg-plugin-type: postOperationModifyDN |
| | | ds-cfg-plugin-type: subordinateModifyDN |
| | | ds-cfg-plugin-type: subordinateDelete |
| | | ds-cfg-attribute-type: member |
| | | ds-cfg-attribute-type: uniqueMember |
| | | ds-cfg-invoke-for-internal-operations: true |
| | |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | attributeTypes: ( 1.3.6.1.4.1.26027.1.1.609 |
| | | NAME 'ds-cfg-plugin-order-subordinate-delete' |
| | | SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 |
| | | SINGLE-VALUE |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 |
| | | NAME 'ds-cfg-access-control-handler' |
| | | SUP top |
| | |
| | | ds-cfg-plugin-order-search-result-entry $ |
| | | ds-cfg-plugin-order-search-result-reference $ |
| | | ds-cfg-plugin-order-subordinate-modify-dn $ |
| | | ds-cfg-plugin-order-subordinate-delete $ |
| | | ds-cfg-plugin-order-intermediate-response ) |
| | | X-ORIGIN 'OpenDS Directory Server' ) |
| | | objectClasses: ( 1.3.6.1.4.1.26027.1.2.112 |
| | |
| | | ! CDDL HEADER END |
| | | ! |
| | | ! |
| | | ! Copyright 2007-2009 Sun Microsystems, Inc. |
| | | ! Copyright 2007-2010 Sun Microsystems, Inc. |
| | | ! --> |
| | | <adm:managed-object name="plugin" plural-name="plugins" |
| | | package="org.opends.server.admin.std" |
| | |
| | | subordinate to the target of a modify DN operation. |
| | | </adm:synopsis> |
| | | </adm:value> |
| | | <adm:value name="subordinatedelete"> |
| | | <adm:synopsis> |
| | | Invoked in the course of deleting a subordinate |
| | | entry of a delete operation. |
| | | </adm:synopsis> |
| | | </adm:value> |
| | | <adm:value name="intermediateresponse"> |
| | | <adm:synopsis> |
| | | Invoked before sending an intermediate repsonse message to |
| | |
| | | ! CDDL HEADER END |
| | | ! |
| | | ! |
| | | ! Copyright 2007-2009 Sun Microsystems, Inc. |
| | | ! Copyright 2007-2010 Sun Microsystems, Inc. |
| | | ! --> |
| | | <adm:managed-object name="plugin-root" plural-name="plugin-roots" |
| | | package="org.opends.server.admin.std" |
| | |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | <adm:property name="plugin-order-subordinate-delete"> |
| | | <adm:synopsis> |
| | | Specifies the order in which subordinate delete plug-ins are to |
| | | be loaded and invoked. |
| | | </adm:synopsis> |
| | | <adm:description> |
| | | The value is a comma-delimited list |
| | | of plug-in names (where the plug-in name is the RDN value from the |
| | | plug-in configuration entry DN). The list can include at most one |
| | | asterisk to indicate the position of any unspecified plug-in (and |
| | | the relative order of those unspecified plug-ins is |
| | | undefined). |
| | | </adm:description> |
| | | <adm:default-behavior> |
| | | <adm:alias> |
| | | <adm:synopsis> |
| | | The order in which subordinate delete plug-ins are loaded |
| | | and invoked is undefined. |
| | | </adm:synopsis> |
| | | </adm:alias> |
| | | </adm:default-behavior> |
| | | <adm:syntax> |
| | | <adm:string /> |
| | | </adm:syntax> |
| | | <adm:profile name="ldap"> |
| | | <ldap:attribute> |
| | | <ldap:name>ds-cfg-plugin-order-subordinate-delete</ldap:name> |
| | | </ldap:attribute> |
| | | </adm:profile> |
| | | </adm:property> |
| | | <adm:property name="plugin-order-intermediate-response"> |
| | | <adm:synopsis> |
| | | Specifies the order in which intermediate response plug-ins are to |
| | |
| | | ! CDDL HEADER END |
| | | ! |
| | | ! |
| | | ! Copyright 2007-2008 Sun Microsystems, Inc. |
| | | ! Copyright 2007-2010 Sun Microsystems, Inc. |
| | | ! --> |
| | | <adm:managed-object name="referential-integrity-plugin" |
| | | plural-name="referential-integrity-plugins" |
| | |
| | | <adm:value>postoperationdelete</adm:value> |
| | | <adm:value>postoperationmodifydn</adm:value> |
| | | <adm:value>subordinatemodifydn</adm:value> |
| | | <adm:value>subordinatedelete</adm:value> |
| | | </adm:defined> |
| | | </adm:default-behavior> |
| | | </adm:property-override> |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-order-startup.synopsis=Specifies the order in which startup plug-ins are to be loaded and invoked. |
| | | property.plugin-order-startup.description=The value is a comma-delimited list of plug-in names (where the plug-in name is the RDN value from the plug-in configuration entry DN). The list can include at most one asterisk to indicate the position of any unspecified plug-in (and the relative order of those unspecified plug-ins is undefined). |
| | | property.plugin-order-startup.default-behavior.alias.synopsis=The order in which startup plug-ins are loaded and invoked is undefined. |
| | | property.plugin-order-subordinate-delete.synopsis=Specifies the order in which subordinate delete plug-ins are to be loaded and invoked. |
| | | property.plugin-order-subordinate-delete.description=The value is a comma-delimited list of plug-in names (where the plug-in name is the RDN value from the plug-in configuration entry DN). The list can include at most one asterisk to indicate the position of any unspecified plug-in (and the relative order of those unspecified plug-ins is undefined). |
| | | property.plugin-order-subordinate-delete.default-behavior.alias.synopsis=The order in which subordinate delete plug-ins are loaded and invoked is undefined. |
| | | property.plugin-order-subordinate-modify-dn.synopsis=Specifies the order in which subordinate modify DN plug-ins are to be loaded and invoked. |
| | | property.plugin-order-subordinate-modify-dn.description=The value is a comma-delimited list of plug-in names (where the plug-in name is the RDN value from the plug-in configuration entry DN). The list can include at most one asterisk to indicate the position of any unspecified plug-in (and the relative order of those unspecified plug-ins is undefined). |
| | | property.plugin-order-subordinate-modify-dn.default-behavior.alias.synopsis=The order in which subordinate modify DN plug-ins are loaded and invoked is undefined. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | | property.profile-action.synopsis=Specifies the action that should be taken by the profiler. |
| | | property.profile-action.description=A value of "start" causes the profiler thread to start collecting data if it is not already active. A value of "stop" causes the profiler thread to stop collecting data and write it to disk, and a value of "cancel" causes the profiler thread to stop collecting data and discard anything that has been captured. These operations occur immediately. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | | property.update-interval.synopsis=Specifies the interval in seconds when referential integrity updates are made. |
| | | property.update-interval.description=If this value is 0, then the updates are made synchronously in the foreground. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | |
| | | property.plugin-type.syntax.enumeration.value.searchresultreference.synopsis=Invoked before sending a search result reference to the client. |
| | | property.plugin-type.syntax.enumeration.value.shutdown.synopsis=Invoked during a graceful Directory Server shutdown. |
| | | property.plugin-type.syntax.enumeration.value.startup.synopsis=Invoked during the Directory Server startup process. |
| | | property.plugin-type.syntax.enumeration.value.subordinatedelete.synopsis=Invoked in the course of deleting a subordinate entry of a delete operation. |
| | | property.plugin-type.syntax.enumeration.value.subordinatemodifydn.synopsis=Invoked in the course of moving or renaming an entry subordinate to the target of a modify DN operation. |
| | | property.type.synopsis=Specifies the type of attributes to check for value uniqueness. |
| | |
| | | SEVERE_ERR_CONFIG_JEB_CACHE_SIZE_TOO_SMALL_194=Configuration \ |
| | | attribute ds-cfg-db-cache-size has a value of %d which is less than \ |
| | | the minimum: %d |
| | | MILD_ERR_JEB_DELETE_ABORTED_BY_SUBORDINATE_PLUGIN_195=A plugin caused the \ |
| | | delete operation to be aborted while deleting a subordinate entry %s |
| | | NOTICE_JEB_IMPORT_LDIF_PHASE_TWO_MEM_REPORT_196=The available memory for phase \ |
| | | two processing is %d bytes. The read ahead cache size is %d bytes calculated \ |
| | | using %d buffers |
| | |
| | | # |
| | | # CDDL HEADER END |
| | | # |
| | | # Copyright 2006-2009 Sun Microsystems, Inc. |
| | | # Copyright 2006-2010 Sun Microsystems, Inc. |
| | | |
| | | |
| | | |
| | |
| | | made to register the Change Number Control plugin with the following plugin \ |
| | | types : %s. However this plugin must be configured with all of the following \ |
| | | plugin types : %s |
| | | SEVERE_ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_EXCEPTION_115=The subordinate \ |
| | | delete plugin defined in configuration entry %s threw an exception when it \ |
| | | was invoked for connection %d operation %d: %s. Processing on this \ |
| | | operation will be terminated |
| | | SEVERE_ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_RETURNED_NULL_116=The \ |
| | | subordinate delete plugin defined in configuration entry %s returned null \ |
| | | when invoked for connection %d operation %s. This is an illegal response, \ |
| | | and processing on this operation will be terminated |
| New file |
| | |
| | | /* |
| | | * 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 2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.api; |
| | | |
| | | import java.util.AbstractMap; |
| | | import java.util.AbstractSet; |
| | | import java.util.Collection; |
| | | import java.util.HashMap; |
| | | import java.util.Iterator; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | | import java.util.NoSuchElementException; |
| | | import java.util.Set; |
| | | import org.opends.server.types.DN; |
| | | |
| | | |
| | | /** |
| | | * The DITCacheMap class implements custom Map for structural |
| | | * storage of arbitrary objects in Directory Information Tree |
| | | * (DIT) like structure. |
| | | * |
| | | * This Map intended usage is for caching various server |
| | | * objects which can be subject to subtree operations |
| | | * like retrieval or removal of all objects under a |
| | | * specific DN. While using a regular Map it would |
| | | * require the entire Map iteration to achieve, this Map |
| | | * implementation maintains such internal structure that |
| | | * subtree operations are more efficient and do not |
| | | * require iterations over the entire map, instead |
| | | * additional subtree operations methods are provided by |
| | | * this Map to do just that. |
| | | * |
| | | * API wise it behaves exactly like a regular Map |
| | | * implementation except for providing additional |
| | | * subtree methods. All required linkage and |
| | | * structuring is performed within this Map |
| | | * implementation itself and not exposed via the |
| | | * API in any way. For example, putting these |
| | | * key/value pairs |
| | | * |
| | | * cn=Object1,ou=Objects,dc=example,dc=com : object1 |
| | | * cn=Object2,ou=Objects,dc=example,dc=com : object2 |
| | | * cn=Object3,ou=Objects,dc=example,dc=com : object3 |
| | | * |
| | | * then invoking a subtree method on this Map with |
| | | * any of these keys |
| | | * |
| | | * ou=Objects,dc=example,dc=com |
| | | * dc=example,dc=com |
| | | * dc=com |
| | | * |
| | | * would bring all three objects previously stored in |
| | | * this map into subtree operation scope. Standard |
| | | * Map API methods can only work with the objects |
| | | * previously stored in this map explicitly. |
| | | * |
| | | * Note that this Map implementation is not |
| | | * synchronized. |
| | | * |
| | | * @param <T> arbitrary object type. |
| | | */ |
| | | public class DITCacheMap<T> extends AbstractMap<DN,T> |
| | | { |
| | | /** |
| | | * Node class for object storage and |
| | | * linking to any subordinate nodes. |
| | | * @param <T> arbitrary storage object. |
| | | */ |
| | | private static final class Node<T> |
| | | { |
| | | // Node DN. |
| | | DN dn; |
| | | // Storage object or null if this node exist |
| | | // only to support the DIT like structuring. |
| | | T element; |
| | | // Parent. |
| | | Node<T> parent; |
| | | // First child. |
| | | Node<T> child; |
| | | // Next sibling. |
| | | Node<T> next; |
| | | // Previous sibling. |
| | | Node<T> previous; |
| | | } |
| | | |
| | | // Map size reflecting only nodes |
| | | // containing non empty elements. |
| | | private int size = 0; |
| | | |
| | | // Backing Map implementation. |
| | | private Map<DN,Node<T>> ditCacheMap; |
| | | |
| | | /** |
| | | * Default contructor. |
| | | */ |
| | | public DITCacheMap() |
| | | { |
| | | ditCacheMap = new HashMap<DN,Node<T>>(); |
| | | } |
| | | |
| | | /** |
| | | * Contructs a new DITCacheMap from a given Map. |
| | | * @param m existing Map to construct new |
| | | * DITCacheMap from. |
| | | */ |
| | | public DITCacheMap(Map<? extends DN, ? extends T> m) |
| | | { |
| | | ditCacheMap = new HashMap<DN,Node<T>>(); |
| | | this.putAll(m); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public int size() |
| | | { |
| | | return size; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean isEmpty() |
| | | { |
| | | return ditCacheMap.isEmpty(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean containsKey(Object key) |
| | | { |
| | | if (get((DN) key) != null) |
| | | { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean containsValue(Object value) |
| | | { |
| | | for (Node<T> node : ditCacheMap.values()) |
| | | { |
| | | if ((node.element != null) && |
| | | node.element.equals(value)) |
| | | { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public T get(Object key) |
| | | { |
| | | Node<T> node = ditCacheMap.get((DN)key); |
| | | if (node != null) |
| | | { |
| | | return node.element; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * Returns a set of stored objects |
| | | * subordinate to subtree DN. |
| | | * @param key subtree DN. |
| | | * @return collection of stored objects |
| | | * subordinate to subtree DN. |
| | | */ |
| | | public Collection<T> getSubtree(DN key) |
| | | { |
| | | return new DITSubtreeSet(key); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public T put(DN key, T value) |
| | | { |
| | | T returnValue = null; |
| | | |
| | | Node<T> existingNode = ditCacheMap.get(key); |
| | | if (existingNode != null) |
| | | { |
| | | returnValue = existingNode.element; |
| | | existingNode.element = value; |
| | | } |
| | | else |
| | | { |
| | | Node<T> node = new Node<T>(); |
| | | node.dn = key; |
| | | node.element = value; |
| | | node.parent = null; |
| | | node.child = null; |
| | | node.next = null; |
| | | node.previous = null; |
| | | |
| | | ditCacheMap.put(key, node); |
| | | size++; |
| | | |
| | | for (DN parentDN = key.getParent(); |
| | | parentDN != null; |
| | | parentDN = parentDN.getParent()) |
| | | { |
| | | Node<T> parentNode = ditCacheMap.get(parentDN); |
| | | if (parentNode != null) |
| | | { |
| | | if (parentNode.child != null) |
| | | { |
| | | Node<T> lastNode = parentNode.child; |
| | | while (lastNode.next != null) |
| | | { |
| | | lastNode = lastNode.next; |
| | | } |
| | | node.previous = lastNode; |
| | | lastNode.next = node; |
| | | } |
| | | else |
| | | { |
| | | parentNode.child = node; |
| | | } |
| | | node.parent = parentNode; |
| | | break; |
| | | } |
| | | else |
| | | { |
| | | parentNode = new Node<T>(); |
| | | parentNode.dn = parentDN; |
| | | parentNode.element = null; |
| | | parentNode.parent = null; |
| | | parentNode.child = node; |
| | | parentNode.next = null; |
| | | parentNode.previous = null; |
| | | ditCacheMap.put(parentDN, parentNode); |
| | | node.parent = parentNode; |
| | | node = parentNode; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return returnValue; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public T remove(Object key) |
| | | { |
| | | T returnValue = null; |
| | | |
| | | Node<T> existingNode = ditCacheMap.get((DN)key); |
| | | if ((existingNode != null) && |
| | | (existingNode.element != null)) |
| | | { |
| | | returnValue = existingNode.element; |
| | | |
| | | try |
| | | { |
| | | if (existingNode.child == null) |
| | | { |
| | | ditCacheMap.remove((DN)key); |
| | | } |
| | | else |
| | | { |
| | | existingNode.element = null; |
| | | return returnValue; |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | size--; |
| | | } |
| | | |
| | | for (DN parentDN = existingNode.dn.getParent(); |
| | | parentDN != null; |
| | | parentDN = parentDN.getParent()) |
| | | { |
| | | Node<T> parentNode = ditCacheMap.get(parentDN); |
| | | if (parentNode.child == existingNode) |
| | | { |
| | | parentNode.child = existingNode.next; |
| | | } |
| | | else |
| | | { |
| | | if (existingNode.next != null) |
| | | { |
| | | existingNode.next.previous = existingNode.previous; |
| | | } |
| | | if (existingNode.previous != null) |
| | | { |
| | | existingNode.previous.next = existingNode.next; |
| | | } |
| | | } |
| | | if ((parentNode.child == null) && |
| | | (parentNode.element == null)) |
| | | { |
| | | existingNode = ditCacheMap.remove(parentDN); |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | return returnValue; |
| | | } |
| | | |
| | | /** |
| | | * Removes a set of stored objects subordinate to subtree DN. |
| | | * @param key subtree DN. |
| | | * @param values collection for removed objects subordinate |
| | | * to subtree DN or <code>null</code>. |
| | | * @return <code>true</code> on success or |
| | | * <code>false</code> otherwise. |
| | | */ |
| | | public boolean removeSubtree(DN key, Collection<? super T> values) |
| | | { |
| | | Node<T> rootNode = ditCacheMap.get(key); |
| | | |
| | | if (rootNode != null) |
| | | { |
| | | if (rootNode.element != null) |
| | | { |
| | | remove(key); |
| | | if (values != null) |
| | | { |
| | | values.add(rootNode.element); |
| | | } |
| | | } |
| | | |
| | | Node<T> node = rootNode.child; |
| | | |
| | | while (node != null) |
| | | { |
| | | if (node.element != null) |
| | | { |
| | | remove(node.dn); |
| | | if (values != null) |
| | | { |
| | | values.add(node.element); |
| | | } |
| | | } |
| | | if (node.child != null) |
| | | { |
| | | node = node.child; |
| | | } |
| | | else |
| | | { |
| | | while ((node.next == null) && |
| | | (node.parent != rootNode)) |
| | | { |
| | | node = node.parent; |
| | | } |
| | | node = node.next; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void putAll(Map<? extends DN, ? extends T> m) |
| | | { |
| | | for (Entry<? extends DN, ? extends T> entry : m.entrySet()) |
| | | { |
| | | put(entry.getKey(), entry.getValue()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void clear() |
| | | { |
| | | ditCacheMap.clear(); |
| | | size = 0; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Set<Entry<DN, T>> entrySet() |
| | | { |
| | | return new DITCacheEntrySet(); |
| | | } |
| | | |
| | | /** |
| | | * EntrySet class implementation for the DITCacheMap. |
| | | */ |
| | | private class DITCacheEntrySet extends AbstractSet<Entry<DN, T>> |
| | | { |
| | | /** |
| | | * Iterator class implementation for the DITCacheEntrySet. |
| | | */ |
| | | private class EntryIterator implements Iterator<Entry<DN, T>> |
| | | { |
| | | private Iterator<Entry<DN, Node<T>>> ditCacheMapIterator; |
| | | private Entry<DN, Node<T>> currentEntry; |
| | | private Entry<DN, Node<T>> nextEntry; |
| | | private boolean hasNext; |
| | | |
| | | /** |
| | | * Default constructor. |
| | | */ |
| | | public EntryIterator() |
| | | { |
| | | ditCacheMapIterator = ditCacheMap.entrySet().iterator(); |
| | | currentEntry = null; |
| | | nextEntry = null; |
| | | hasNext = false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasNext() |
| | | { |
| | | if (hasNext) |
| | | { |
| | | return true; |
| | | } |
| | | while (ditCacheMapIterator.hasNext()) |
| | | { |
| | | Entry<DN, Node<T>> entry = ditCacheMapIterator.next(); |
| | | Node<T> node = entry.getValue(); |
| | | if ((node != null) && (node.element != null)) |
| | | { |
| | | nextEntry = entry; |
| | | hasNext = true; |
| | | return true; |
| | | } |
| | | } |
| | | nextEntry = null; |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Entry<DN, T> next() |
| | | { |
| | | if (nextEntry != null) |
| | | { |
| | | Node<T> node = nextEntry.getValue(); |
| | | currentEntry = nextEntry; |
| | | nextEntry = null; |
| | | hasNext = false; |
| | | return new DITCacheMapEntry(node.dn, node.element); |
| | | } |
| | | while (ditCacheMapIterator.hasNext()) |
| | | { |
| | | Entry<DN, Node<T>> entry = ditCacheMapIterator.next(); |
| | | Node<T> node = entry.getValue(); |
| | | if ((node != null) && (node.element != null)) |
| | | { |
| | | currentEntry = entry; |
| | | hasNext = false; |
| | | return new DITCacheMapEntry(node.dn, node.element); |
| | | } |
| | | } |
| | | throw new NoSuchElementException(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void remove() |
| | | { |
| | | if (currentEntry != null) |
| | | { |
| | | Entry<DN, Node<T>> oldIteratorEntry = null; |
| | | if (hasNext()) |
| | | { |
| | | oldIteratorEntry = nextEntry; |
| | | } |
| | | if (DITCacheMap.this.remove(currentEntry.getKey()) != null) |
| | | { |
| | | ditCacheMapIterator = ditCacheMap.entrySet().iterator(); |
| | | currentEntry = null; |
| | | nextEntry = null; |
| | | hasNext = false; |
| | | while (hasNext()) |
| | | { |
| | | Entry<DN, T> newIteratorEntry = next(); |
| | | if ((oldIteratorEntry != null) && |
| | | oldIteratorEntry.getKey().equals( |
| | | newIteratorEntry.getKey()) && |
| | | oldIteratorEntry.getValue().element.equals( |
| | | newIteratorEntry.getValue())) |
| | | { |
| | | nextEntry = currentEntry; |
| | | hasNext = true; |
| | | return; |
| | | } |
| | | } |
| | | currentEntry = null; |
| | | nextEntry = null; |
| | | hasNext = false; |
| | | return; |
| | | } |
| | | } |
| | | throw new IllegalStateException(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int size() |
| | | { |
| | | return DITCacheMap.this.size(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Iterator<Entry<DN, T>> iterator() |
| | | { |
| | | return new EntryIterator(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Map.Entry class implementation for the DITCacheMap. |
| | | */ |
| | | private class DITCacheMapEntry implements Map.Entry<DN, T> |
| | | { |
| | | private DN key; |
| | | private T value; |
| | | |
| | | /** |
| | | * Constructs a new DITCacheMapEntry |
| | | * with given key and value. |
| | | * @param key Map.Entry key. |
| | | * @param value Map.Entry value. |
| | | */ |
| | | public DITCacheMapEntry(DN key, T value) |
| | | { |
| | | this.key = key; |
| | | this.value = value; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public DN getKey() |
| | | { |
| | | return key; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public T getValue() |
| | | { |
| | | return value; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public T setValue(T value) |
| | | { |
| | | Node<T> node = ditCacheMap.get(key); |
| | | T oldValue = this.value; |
| | | node.element = value; |
| | | this.value = value; |
| | | return oldValue; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * SubtreeSet class implementation. |
| | | */ |
| | | private class DITSubtreeSet extends AbstractSet<T> |
| | | { |
| | | // Set key. |
| | | private DN key; |
| | | |
| | | /** |
| | | * Default constructor. |
| | | */ |
| | | public DITSubtreeSet() |
| | | { |
| | | this.key = null; |
| | | } |
| | | |
| | | /** |
| | | * Keyed constructor. |
| | | * @param key to construct |
| | | * this set from. |
| | | */ |
| | | public DITSubtreeSet(DN key) |
| | | { |
| | | this.key = key; |
| | | } |
| | | |
| | | /** |
| | | * Iterator class implementation for SubtreeSet. |
| | | */ |
| | | private class SubtreeSetIterator implements Iterator<T> |
| | | { |
| | | // Iterator key. |
| | | private DN key; |
| | | |
| | | // Iterator root node. |
| | | private Node<T> rootNode; |
| | | |
| | | // Iterator current node. |
| | | private Node<T> node; |
| | | |
| | | /** |
| | | * Default constructor. |
| | | */ |
| | | public SubtreeSetIterator() |
| | | { |
| | | this.key = DITSubtreeSet.this.key; |
| | | rootNode = ditCacheMap.get(this.key); |
| | | node = rootNode; |
| | | } |
| | | |
| | | /** |
| | | * Keyed constructor. |
| | | * @param key to cue this |
| | | * iterator from. |
| | | */ |
| | | public SubtreeSetIterator(DN key) |
| | | { |
| | | this.key = key; |
| | | rootNode = ditCacheMap.get(this.key); |
| | | node = rootNode; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean hasNext() |
| | | { |
| | | if (rootNode != null) |
| | | { |
| | | while (node != null) |
| | | { |
| | | if (node.element != null) |
| | | { |
| | | return true; |
| | | } |
| | | if (node.child != null) |
| | | { |
| | | node = node.child; |
| | | } |
| | | else |
| | | { |
| | | if (node != rootNode) |
| | | { |
| | | while ((node.next == null) && |
| | | (node.parent != rootNode)) |
| | | { |
| | | node = node.parent; |
| | | } |
| | | } |
| | | node = node.next; |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public T next() |
| | | { |
| | | T element = null; |
| | | |
| | | if (rootNode != null) |
| | | { |
| | | while (node != null) |
| | | { |
| | | if (node.element != null) |
| | | { |
| | | element = node.element; |
| | | } |
| | | else |
| | | { |
| | | element = null; |
| | | } |
| | | if (node.child != null) |
| | | { |
| | | node = node.child; |
| | | } |
| | | else |
| | | { |
| | | if (node != rootNode) |
| | | { |
| | | while ((node.next == null) && |
| | | (node.parent != rootNode)) |
| | | { |
| | | node = node.parent; |
| | | } |
| | | } |
| | | node = node.next; |
| | | } |
| | | if (element != null) |
| | | { |
| | | return element; |
| | | } |
| | | } |
| | | } |
| | | throw new NoSuchElementException(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public void remove() |
| | | { |
| | | throw new UnsupportedOperationException(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public Iterator<T> iterator() |
| | | { |
| | | return new SubtreeSetIterator(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public int size() |
| | | { |
| | | int size = 0; |
| | | |
| | | Iterator<T> iterator = new SubtreeSetIterator(this.key); |
| | | while (iterator.hasNext()) |
| | | { |
| | | iterator.next(); |
| | | size++; |
| | | } |
| | | |
| | | return size; |
| | | } |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api; |
| | | import org.opends.messages.Message; |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the DN of the entry that contains the definition for |
| | | * this group. |
| | | * |
| | | * @param groupDN The DN of the entry that contains the |
| | | * definition for this group. |
| | | */ |
| | | public abstract void setGroupDN(DN groupDN); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Indicates whether this group supports nesting other groups, such |
| | | * that the members of the nested groups will also be considered |
| | | * members of this group. |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api.plugin; |
| | | import org.opends.messages.Message; |
| | |
| | | import org.opends.server.admin.std.server.PluginCfg; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DeleteOperation; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.types.operation.*; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Performs any necessary processing that should be done whenever a |
| | | * subordinate entry is deleted as part of subtree delete operation. |
| | | * |
| | | * @param deleteOperation The delete operation with which the |
| | | * subordinate entry is associated. |
| | | * @param entry The subordinate entry being deleted. |
| | | * |
| | | * @return Information about the result of the plugin processing. |
| | | */ |
| | | public PluginResult.SubordinateDelete |
| | | processSubordinateDelete(DeleteOperation |
| | | deleteOperation, Entry entry) |
| | | { |
| | | Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.get( |
| | | String.valueOf(pluginDN), |
| | | PluginType.SUBORDINATE_MODIFY_DN.getName()); |
| | | throw new UnsupportedOperationException(message.toString()); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Performs any necessary processing that should be done after the |
| | | * Directory Server has completed the core processing for a modify |
| | | * DN operation but before the response has been sent to the client. |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api.plugin; |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Defines a subordinate delete plugin result for core server |
| | | * operation processing consisting of either continue, skip |
| | | * further plugins, or stop operation processing with a result |
| | | * code, matched DN, referral URLs, and error message. |
| | | */ |
| | | public static final class SubordinateDelete |
| | | { |
| | | // Whether to continue operation processing. |
| | | private final boolean continueProcessing; |
| | | |
| | | // Whether to invoke the rest of the plugins. |
| | | private final boolean continuePluginProcessing; |
| | | |
| | | // An message explaining why processing should stop. |
| | | private final Message errorMessage; |
| | | |
| | | // The matched DN for this result. |
| | | private final DN matchedDN; |
| | | |
| | | // The set of referral URLs for this result. |
| | | private final List<String> referralURLs; |
| | | |
| | | // The result code for this result. |
| | | private final ResultCode resultCode; |
| | | |
| | | private static SubordinateDelete DEFAULT_RESULT = |
| | | new SubordinateDelete(true, true, null, null, null, null); |
| | | |
| | | /** |
| | | * Construct a new subordinate delete plugin result. |
| | | * |
| | | * @param continueProcessing Whether to continue startup. |
| | | * @param continuePluginProcessing Whether to invoke the rest |
| | | * of the plugins. |
| | | * @param errorMessage An message explaining why processing |
| | | * should stop. |
| | | * @param resultCode The result code for this result. |
| | | * @param matchedDN The matched DN for this result. |
| | | * @param referralURLs The set of referral URLs for this result. |
| | | * stop. |
| | | */ |
| | | private SubordinateDelete(boolean continueProcessing, |
| | | boolean continuePluginProcessing, |
| | | Message errorMessage, |
| | | ResultCode resultCode, DN matchedDN, |
| | | List<String> referralURLs) |
| | | { |
| | | this.continueProcessing = continueProcessing; |
| | | this.errorMessage = errorMessage; |
| | | this.continuePluginProcessing = continuePluginProcessing; |
| | | this.resultCode = resultCode; |
| | | this.matchedDN = matchedDN; |
| | | this.referralURLs = referralURLs; |
| | | } |
| | | |
| | | /** |
| | | * Defines a continue processing subordinate delete plugin |
| | | * result. |
| | | * |
| | | * @return a continue processing subordinate delete plugin |
| | | * result. |
| | | */ |
| | | public static SubordinateDelete continueOperationProcessing() |
| | | { |
| | | return DEFAULT_RESULT; |
| | | } |
| | | |
| | | /** |
| | | * Defines a skip further plugin processing subordinate delete |
| | | * plugin result. |
| | | * |
| | | * @return a skip further plugin processing subordinate delete |
| | | * plugin result. |
| | | */ |
| | | public static SubordinateDelete skipFurtherPluginProcesssing() |
| | | { |
| | | return new SubordinateDelete(true, false, null, null, null, |
| | | null); |
| | | } |
| | | |
| | | /** |
| | | * Defines a new stop processing subordinate delete plugin |
| | | * result. |
| | | * |
| | | * @param resultCode The result code for this result. |
| | | * @param errorMessage An message explaining why processing |
| | | * should stop. |
| | | * @param matchedDN The matched DN for this result. |
| | | * @param referralURLs The set of referral URLs for this result. |
| | | * |
| | | * @return a new stop processing subordinate delete plugin |
| | | * result. |
| | | */ |
| | | public static SubordinateDelete stopProcessing( |
| | | ResultCode resultCode, Message errorMessage, DN matchedDN, |
| | | List<String> referralURLs) |
| | | { |
| | | return new SubordinateDelete(false, false, errorMessage, |
| | | resultCode, matchedDN, referralURLs); |
| | | } |
| | | |
| | | /** |
| | | * Contrust a new stop processing subordinate delete plugin |
| | | * result. |
| | | * |
| | | * @param resultCode The result code for this result. |
| | | * @param errorMessage An message explaining why processing |
| | | * should stop. |
| | | * |
| | | * @return a new stop processing subordinate delete plugin |
| | | * result. |
| | | */ |
| | | public static SubordinateDelete stopProcessing( |
| | | ResultCode resultCode, Message errorMessage) |
| | | { |
| | | return new SubordinateDelete(false, false, errorMessage, |
| | | resultCode, null, null); |
| | | } |
| | | |
| | | /** |
| | | * Whether to continue operation processing. |
| | | * |
| | | * @return <code>true</code> if processing should continue |
| | | * or <code>false</code> otherwise. |
| | | */ |
| | | public boolean continueProcessing() |
| | | { |
| | | return continueProcessing; |
| | | } |
| | | |
| | | /** |
| | | * Whether to invoke the rest of the plugins. |
| | | * |
| | | * @return <code>true</code> if the rest of the plugins should |
| | | * be invoked for <code>false</code> to skip the rest of the |
| | | * plugins. |
| | | */ |
| | | public boolean continuePluginProcessing() |
| | | { |
| | | return continuePluginProcessing; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the error message if <code>continueProcessing</code> |
| | | * returned <code>false</code>. |
| | | * |
| | | * @return An error message explaining why processing should |
| | | * stop or <code>null</code> if none is provided. |
| | | */ |
| | | public Message getErrorMessage() |
| | | { |
| | | return errorMessage; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the result code for the operation |
| | | * if <code>continueProcessing</code> returned <code>false</code>. |
| | | * |
| | | * @return the result code for the operation or <code>null</code> |
| | | * if none is provided. |
| | | */ |
| | | public ResultCode getResultCode() |
| | | { |
| | | return resultCode; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the matched DN for the operation |
| | | * if <code>continueProcessing</code> returned <code>false</code>. |
| | | * |
| | | * @return the matched DN for the operation or <code>null</code> |
| | | * if none is provided. |
| | | */ |
| | | public DN getMatchedDN() |
| | | { |
| | | return matchedDN; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves the referral URLs for the operation |
| | | * if <code>continueProcessing</code> returned <code>false</code>. |
| | | * |
| | | * @return the refferal URLs for the operation or |
| | | * <code>null</code> if none is provided. |
| | | */ |
| | | public List<String> getReferralURLs() |
| | | { |
| | | return referralURLs; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Defines an intermediate response plugin result for core server |
| | | * operation processing consisting of either continue, skip further |
| | | * plugins, or stop operation processing with a result code, |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api.plugin; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * The plugin type for plugins that are to be invoked on each |
| | | * subordinate entry that is deleted as part of a subtree |
| | | * delete operation. |
| | | */ |
| | | SUBORDINATE_DELETE("subordinatedelete"), |
| | | |
| | | |
| | | |
| | | /** |
| | | * The plugin type for plugins that are to be invoked before each |
| | | * intermediate response message is sent to a client. |
| | | */ |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.authorization.dseecompat; |
| | |
| | | import static org.opends.server.authorization.dseecompat.AciHandler.*; |
| | | import static org.opends.server.loggers.ErrorLogger.logError; |
| | | import static org.opends.messages.AccessControlMessages.*; |
| | | import org.opends.server.api.DITCacheMap; |
| | | import org.opends.server.types.*; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | |
| | | /** |
| | | * The AciList class performs caching of the ACI attribute values |
| | |
| | | * A map containing all the ACIs. |
| | | * We use the copy-on-write technique to avoid locking when reading. |
| | | */ |
| | | private volatile LinkedHashMap<DN, List<Aci>> aciList = |
| | | new LinkedHashMap<DN, List<Aci>>(); |
| | | private volatile DITCacheMap<List<Aci>> aciList = |
| | | new DITCacheMap<List<Aci>>(); |
| | | |
| | | /* |
| | | * Lock to protect internal data structures. |
| | | */ |
| | | private final ReentrantReadWriteLock lock = |
| | | new ReentrantReadWriteLock(); |
| | | |
| | | /* |
| | | * The configuration DN used to compare against the global ACI entry DN. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Accessor to the ACI list intended to be called from within unsynchronized |
| | | * read-only methods. |
| | | * @return The current ACI list. |
| | | */ |
| | | private LinkedHashMap<DN, List<Aci>> getList() { |
| | | return aciList; |
| | | } |
| | | |
| | | /** |
| | | * Used by synchronized write methods to make a copy of the ACI list. |
| | | * @return A copy of the ACI list. |
| | | */ |
| | | private LinkedHashMap<DN,List<Aci>> copyList() { |
| | | return new LinkedHashMap<DN, List<Aci>>(aciList); |
| | | } |
| | | |
| | | /** |
| | | * Using the base DN, return a list of ACIs that are candidates for |
| | | * evaluation by walking up from the base DN towards the root of the |
| | | * DIT gathering ACIs on parents. Global ACIs use the NULL DN as the key |
| | |
| | | public LinkedList<Aci> getCandidateAcis(DN baseDN) { |
| | | LinkedList<Aci> candidates = new LinkedList<Aci>(); |
| | | if(baseDN == null) |
| | | { |
| | | return candidates; |
| | | } |
| | | |
| | | // Save a reference to the current ACI list, in case it gets changed. |
| | | LinkedHashMap<DN, List<Aci>> aciList = getList(); |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | //Save the baseDN in case we need to evaluate a global ACI. |
| | | DN entryDN=baseDN; |
| | | while(baseDN != null) { |
| | |
| | | if(targets != null) { |
| | | boolean ret=AciTargets.isTargetApplicable(aci, targets, |
| | | entryDN); |
| | | if(ret) |
| | | if (ret) { |
| | | candidates.add(aci); //Add this ACI to the candidates. |
| | | } |
| | | } |
| | | } else |
| | | } |
| | | } else { |
| | | candidates.addAll(acis); |
| | | } |
| | | if(baseDN.isNullDN()) |
| | | } |
| | | if(baseDN.isNullDN()) { |
| | | break; |
| | | } |
| | | DN parentDN=baseDN.getParent(); |
| | | if(parentDN == null) |
| | | if(parentDN == null) { |
| | | baseDN=DN.nullDN(); |
| | | else |
| | | } else { |
| | | baseDN=parentDN; |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | |
| | | return candidates; |
| | | } |
| | | |
| | |
| | | * exceptions. |
| | | * @return The number of valid ACI attribute values added to the ACI list. |
| | | */ |
| | | public synchronized int addAci(List<? extends Entry> entries, |
| | | public int addAci(List<? extends Entry> entries, |
| | | LinkedList<Message> failedACIMsgs) |
| | | { |
| | | // Copy the ACI list. |
| | | LinkedHashMap<DN,List<Aci>> aciCopy = copyList(); |
| | | |
| | | int validAcis=0; |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | for (Entry entry : entries) { |
| | | DN dn=entry.getDN(); |
| | | List<Attribute> attributeList = |
| | | entry.getOperationalAttribute(AciHandler.aciType); |
| | | validAcis += addAciAttributeList(aciCopy, dn, configDN, |
| | | validAcis += addAciAttributeList(aciList, dn, configDN, |
| | | attributeList, failedACIMsgs); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | |
| | | // Replace the ACI list with the copy. |
| | | aciList = aciCopy; |
| | | return validAcis; |
| | | } |
| | | |
| | |
| | | * @param acis A set of ACIs to add to the ACI list. |
| | | * |
| | | */ |
| | | public synchronized void addAci(DN dn, SortedSet<Aci> acis) { |
| | | public void addAci(DN dn, SortedSet<Aci> acis) { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | aciList.put(dn, new LinkedList<Aci>(acis)); |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Add all of an entry's ACI (global or regular) attribute values to the |
| | |
| | | * exceptions. |
| | | * @return The number of valid ACI attribute values added to the ACI list. |
| | | */ |
| | | public synchronized int addAci(Entry entry, boolean hasAci, |
| | | public int addAci(Entry entry, boolean hasAci, |
| | | boolean hasGlobalAci, |
| | | LinkedList<Message> failedACIMsgs) { |
| | | int validAcis=0; |
| | | |
| | | // Copy the ACI list. |
| | | LinkedHashMap<DN,List<Aci>> aciCopy = copyList(); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | //Process global "ds-cfg-global-aci" attribute type. The oldentry |
| | | //DN is checked to verify it is equal to the config DN. If not those |
| | | //attributes are skipped. |
| | | if(hasGlobalAci && entry.getDN().equals(configDN)) { |
| | | List<Attribute> attributeList = entry.getAttribute(globalAciType); |
| | | validAcis = addAciAttributeList(aciCopy, DN.nullDN(), configDN, |
| | | validAcis = addAciAttributeList(aciList, DN.nullDN(), configDN, |
| | | attributeList, failedACIMsgs); |
| | | } |
| | | |
| | | if(hasAci) { |
| | | List<Attribute> attributeList = entry.getAttribute(aciType); |
| | | validAcis += addAciAttributeList(aciCopy, entry.getDN(), configDN, |
| | | validAcis += addAciAttributeList(aciList, entry.getDN(), configDN, |
| | | attributeList, failedACIMsgs); |
| | | } |
| | | // Replace the ACI list with the copy. |
| | | aciList = aciCopy; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | |
| | | return validAcis; |
| | | } |
| | | |
| | |
| | | * exceptions. |
| | | * @return The number of valid attribute values added to the ACI list. |
| | | */ |
| | | private static int addAciAttributeList(LinkedHashMap<DN,List<Aci>> aciList, |
| | | private static int addAciAttributeList(DITCacheMap<List<Aci>> aciList, |
| | | DN dn, DN configDN, |
| | | List<Attribute> attributeList, |
| | | LinkedList<Message> failedACIMsgs) { |
| | |
| | | * @param hasGlobalAci True if the "ds-cfg-global-aci" attribute type was |
| | | * seen in the entry. |
| | | */ |
| | | public synchronized void modAciOldNewEntry(Entry oldEntry, Entry newEntry, |
| | | public void modAciOldNewEntry(Entry oldEntry, Entry newEntry, |
| | | boolean hasAci, |
| | | boolean hasGlobalAci) { |
| | | |
| | | // Copy the ACI list. |
| | | LinkedHashMap<DN,List<Aci>> aciCopy = copyList(); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | LinkedList<Message>failedACIMsgs=new LinkedList<Message>(); |
| | | //Process "aci" attribute types. |
| | | if(hasAci) { |
| | | aciCopy.remove(oldEntry.getDN()); |
| | | aciList.remove(oldEntry.getDN()); |
| | | List<Attribute> attributeList = |
| | | newEntry.getOperationalAttribute(aciType); |
| | | addAciAttributeList(aciCopy,newEntry.getDN(), configDN, |
| | | addAciAttributeList(aciList,newEntry.getDN(), configDN, |
| | | attributeList, failedACIMsgs); |
| | | } |
| | | //Process global "ds-cfg-global-aci" attribute type. The oldentry |
| | | //DN is checked to verify it is equal to the config DN. If not those |
| | | //attributes are skipped. |
| | | if(hasGlobalAci && oldEntry.getDN().equals(configDN)) { |
| | | aciCopy.remove(DN.nullDN()); |
| | | aciList.remove(DN.nullDN()); |
| | | List<Attribute> attributeList = |
| | | newEntry.getAttribute(globalAciType); |
| | | addAciAttributeList(aciCopy, DN.nullDN(), configDN, |
| | | addAciAttributeList(aciList, DN.nullDN(), configDN, |
| | | attributeList, failedACIMsgs); |
| | | } |
| | | // Replace the ACI list with the copy. |
| | | aciList = aciCopy; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param dn The DN to use as the key. |
| | | * @param acis The ACI to be added. |
| | | */ |
| | | private static void addAci(LinkedHashMap<DN,List<Aci>> aciList, DN dn, |
| | | private static void addAci(DITCacheMap<List<Aci>> aciList, DN dn, |
| | | List<Aci> acis) |
| | | { |
| | | if(aciList.containsKey(dn)) { |
| | |
| | | * seen in the entry. |
| | | * @return True if the ACI set was deleted. |
| | | */ |
| | | public synchronized boolean removeAci(Entry entry, boolean hasAci, |
| | | public boolean removeAci(Entry entry, boolean hasAci, |
| | | boolean hasGlobalAci) { |
| | | // Copy the ACI list. |
| | | LinkedHashMap<DN,List<Aci>> aciCopy = copyList(); |
| | | DN entryDN = entry.getDN(); |
| | | |
| | | if(hasGlobalAci && entry.getDN().equals(configDN) && |
| | | aciCopy.remove(DN.nullDN()) == null) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | if (hasGlobalAci && entryDN.equals(configDN) && |
| | | aciList.remove(DN.nullDN()) == null) |
| | | { |
| | | return false; |
| | | if(hasAci && aciCopy.remove(entry.getDN()) == null) |
| | | } |
| | | if (hasAci && aciList.remove(entryDN) == null) |
| | | { |
| | | return false; |
| | | // Replace the ACI list with the copy. |
| | | aciList = aciCopy; |
| | | } |
| | | if (!hasGlobalAci && !hasAci) |
| | | { |
| | | return aciList.removeSubtree(entryDN, null); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | |
| | | * @param backend The backend to check if each DN is handled by that |
| | | * backend. |
| | | */ |
| | | public synchronized void removeAci(Backend backend) { |
| | | // Copy the ACI list. |
| | | LinkedHashMap<DN,List<Aci>> aciCopy = copyList(); |
| | | public void removeAci(Backend backend) { |
| | | |
| | | Iterator<Map.Entry<DN,List<Aci>>> iterator = aciCopy.entrySet().iterator(); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Iterator<Map.Entry<DN,List<Aci>>> iterator = |
| | | aciList.entrySet().iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | Map.Entry<DN,List<Aci>> mapEntry = iterator.next(); |
| | |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | |
| | | // Replace the ACI list with the copy. |
| | | aciList = aciCopy; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | * @param oldDN The DN of the original entry that was moved. |
| | | * @param newDN The DN of the new entry. |
| | | */ |
| | | public synchronized void renameAci(DN oldDN, DN newDN ) { |
| | | LinkedHashMap<DN, List<Aci>> newCopyList = |
| | | new LinkedHashMap<DN, List<Aci>>(); |
| | | public void renameAci(DN oldDN, DN newDN ) { |
| | | |
| | | int oldRDNCount=oldDN.getNumComponents(); |
| | | int newRDNCount=newDN.getNumComponents(); |
| | | for (Map.Entry<DN,List<Aci>> hashEntry : aciList.entrySet()) { |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Map<DN,List<Aci>> tempAciList = new HashMap<DN,List<Aci>>(); |
| | | Iterator<Map.Entry<DN,List<Aci>>> iterator = |
| | | aciList.entrySet().iterator(); |
| | | while (iterator.hasNext()) { |
| | | Map.Entry<DN,List<Aci>> hashEntry = iterator.next(); |
| | | if(hashEntry.getKey().isDescendantOf(oldDN)) { |
| | | int keyRDNCount=hashEntry.getKey().getNumComponents(); |
| | | int keepRDNCount=keyRDNCount - oldRDNCount; |
| | | RDN[] newRDNs = new RDN[keepRDNCount + newRDNCount]; |
| | | for (int i=0; i < keepRDNCount; i++) |
| | | for (int i=0; i < keepRDNCount; i++) { |
| | | newRDNs[i] = hashEntry.getKey().getRDN(i); |
| | | for (int i=keepRDNCount, j=0; j < newRDNCount; i++,j++) |
| | | } |
| | | for (int i=keepRDNCount, j=0; j < newRDNCount; i++,j++) { |
| | | newRDNs[i] = newDN.getRDN(j); |
| | | } |
| | | DN relocateDN=new DN(newRDNs); |
| | | List<Aci> acis = new LinkedList<Aci>(); |
| | | for(Aci aci : hashEntry.getValue()) { |
| | |
| | | logError(message); |
| | | } |
| | | } |
| | | newCopyList.put(relocateDN, acis); |
| | | } else |
| | | newCopyList.put(hashEntry.getKey(), hashEntry.getValue()); |
| | | tempAciList.put(relocateDN, acis); |
| | | iterator.remove(); |
| | | } |
| | | // Replace the ACI list with the copy. |
| | | aciList = newCopyList; |
| | | } |
| | | aciList.putAll(tempAciList); |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | |
| | | private void doPostDelete(Entry deletedEntry) |
| | | { |
| | | // This entry might have both global and aci attribute types. |
| | | boolean hasAci, hasGlobalAci = false; |
| | | if ((hasAci = deletedEntry |
| | | .hasOperationalAttribute(AciHandler.aciType)) |
| | | || (hasGlobalAci = deletedEntry |
| | | .hasAttribute(AciHandler.globalAciType))) |
| | | { |
| | | boolean hasAci = deletedEntry.hasOperationalAttribute( |
| | | AciHandler.aciType); |
| | | boolean hasGlobalAci = deletedEntry.hasAttribute( |
| | | AciHandler.globalAciType); |
| | | aciList.removeAci(deletedEntry, hasAci, hasGlobalAci); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | */ |
| | | EntryID entryID = new EntryID(data); |
| | | DN subordinateDN = DN.decode(ByteString.wrap(key.getData())); |
| | | |
| | | // Invoke any subordinate delete plugins on the entry. |
| | | if (!deleteOperation.isSynchronizationOperation()) |
| | | { |
| | | Entry subordinateEntry = id2entry.get( |
| | | txn, entryID, LockMode.DEFAULT); |
| | | PluginConfigManager pluginManager = |
| | | DirectoryServer.getPluginConfigManager(); |
| | | PluginResult.SubordinateDelete pluginResult = |
| | | pluginManager.invokeSubordinateDeletePlugins( |
| | | deleteOperation, subordinateEntry); |
| | | |
| | | if (!pluginResult.continueProcessing()) |
| | | { |
| | | Message message = |
| | | ERR_JEB_DELETE_ABORTED_BY_SUBORDINATE_PLUGIN.get( |
| | | subordinateDN.toString()); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), message); |
| | | } |
| | | } |
| | | |
| | | deleteEntry(txn, indexBuffer, true, entryDN, subordinateDN, entryID); |
| | | subordinateEntriesDeleted++; |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.core; |
| | | import java.util.HashSet; |
| | | import java.util.Set; |
| | | import org.opends.messages.Message; |
| | | |
| | | |
| | | |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.CopyOnWriteArraySet; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | |
| | | import org.opends.server.api.ChangeNotificationListener; |
| | | import org.opends.server.api.ClientConnection; |
| | | import org.opends.server.api.DITCacheMap; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.types.DisconnectReason; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.operation.PostResponseAddOperation; |
| | | import org.opends.server.types.operation.PostResponseDeleteOperation; |
| | |
| | | import org.opends.server.types.operation.PostResponseModifyDNOperation; |
| | | |
| | | import static org.opends.messages.CoreMessages.*; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | |
| | | /** |
| | | * This class provides a data structure which maps an authenticated user DN to |
| | | * the set of client connections authenticated as that user. Note that a single |
| | |
| | | public class AuthenticatedUsers |
| | | implements ChangeNotificationListener |
| | | { |
| | | /** |
| | | * The tracer object for the debug logger. |
| | | */ |
| | | private static final DebugTracer TRACER = getTracer(); |
| | | |
| | | // The mapping between authenticated user DNs and the associated client |
| | | // connection objects. |
| | | private ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>> |
| | | userMap; |
| | | private DITCacheMap<CopyOnWriteArraySet<ClientConnection>> userMap; |
| | | |
| | | // Lock to protect internal data structures. |
| | | private final ReentrantReadWriteLock lock; |
| | | |
| | | |
| | | /** |
| | |
| | | */ |
| | | public AuthenticatedUsers() |
| | | { |
| | | userMap = new ConcurrentHashMap<DN,CopyOnWriteArraySet<ClientConnection>>(); |
| | | userMap = new DITCacheMap<CopyOnWriteArraySet<ClientConnection>>(); |
| | | lock = new ReentrantReadWriteLock(); |
| | | |
| | | DirectoryServer.registerChangeNotificationListener(this); |
| | | } |
| | |
| | | * @param clientConnection The client connection over which the user is |
| | | * authenticated. |
| | | */ |
| | | public synchronized void put(DN userDN, ClientConnection clientConnection) |
| | | public void put(DN userDN, ClientConnection clientConnection) |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = |
| | | userMap.get(userDN); |
| | | if (connectionSet == null) |
| | | { |
| | | connectionSet = new CopyOnWriteArraySet<ClientConnection>(); |
| | |
| | | connectionSet.add(clientConnection); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | * @param clientConnection The client connection over which the user is |
| | | * authenticated. |
| | | */ |
| | | public synchronized void remove(DN userDN, ClientConnection clientConnection) |
| | | public void remove(DN userDN, ClientConnection clientConnection) |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = userMap.get(userDN); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = |
| | | userMap.get(userDN); |
| | | if (connectionSet != null) |
| | | { |
| | | connectionSet.remove(clientConnection); |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | */ |
| | | synchronized CopyOnWriteArraySet<ClientConnection> get(DN userDN) |
| | | { |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | return userMap.get(userDN); |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | PostResponseDeleteOperation deleteOperation, |
| | | Entry entry) |
| | | { |
| | | // Identify any client connections that may be authenticated or |
| | | // authorized as the user whose entry has been deleted and terminate them. |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = |
| | | userMap.remove(entry.getDN()); |
| | | if (connectionSet != null) |
| | | // Identify any client connections that may be authenticated |
| | | // or authorized as the user whose entry has been deleted and |
| | | // terminate them. |
| | | Set<CopyOnWriteArraySet<ClientConnection>> arraySet = |
| | | new HashSet<CopyOnWriteArraySet<ClientConnection>>(); |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | userMap.removeSubtree(entry.getDN(), arraySet); |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | for (CopyOnWriteArraySet<ClientConnection> |
| | | connectionSet : arraySet) |
| | | { |
| | | for (ClientConnection conn : connectionSet) |
| | | { |
| | |
| | | PostResponseModifyOperation modifyOperation, |
| | | Entry oldEntry, Entry newEntry) |
| | | { |
| | | // Identify any client connections that may be authenticated or authorized |
| | | // as the user whose entry has been modified and update them with the latest |
| | | // version of the entry. |
| | | // Identify any client connections that may be authenticated |
| | | // or authorized as the user whose entry has been modified |
| | | // and update them with the latest version of the entry. |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = |
| | | userMap.get(oldEntry.getDN()); |
| | | if (connectionSet != null) |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | PostResponseModifyDNOperation modifyDNOperation, |
| | | Entry oldEntry, Entry newEntry) |
| | | { |
| | | // Identify any client connections that may be authenticated or authorized |
| | | // as the user whose entry has been modified and update them with the latest |
| | | // version of the entry. |
| | | CopyOnWriteArraySet<ClientConnection> connectionSet = |
| | | userMap.remove(oldEntry.getDN()); |
| | | if (connectionSet != null) |
| | | { |
| | | synchronized (this) |
| | | { |
| | | CopyOnWriteArraySet<ClientConnection> existingNewSet = |
| | | userMap.get(newEntry.getDN()); |
| | | if (existingNewSet == null) |
| | | { |
| | | userMap.put(newEntry.getDN(), connectionSet); |
| | | } |
| | | else |
| | | { |
| | | existingNewSet.addAll(connectionSet); |
| | | } |
| | | } |
| | | String oldDNString = oldEntry.getDN().toNormalizedString(); |
| | | String newDNString = newEntry.getDN().toNormalizedString(); |
| | | |
| | | // Identify any client connections that may be authenticated |
| | | // or authorized as the user whose entry has been modified |
| | | // and update them with the latest version of the entry. |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Set<CopyOnWriteArraySet<ClientConnection>> arraySet = |
| | | new HashSet<CopyOnWriteArraySet<ClientConnection>>(); |
| | | userMap.removeSubtree(oldEntry.getDN(), arraySet); |
| | | for (CopyOnWriteArraySet<ClientConnection> |
| | | connectionSet : arraySet) |
| | | { |
| | | DN authNDN = null; |
| | | DN authZDN = null; |
| | | DN newAuthNDN = null; |
| | | DN newAuthZDN = null; |
| | | CopyOnWriteArraySet<ClientConnection> newAuthNSet = null; |
| | | CopyOnWriteArraySet<ClientConnection> newAuthZSet = null; |
| | | for (ClientConnection conn : connectionSet) |
| | | { |
| | | conn.updateAuthenticationInfo(oldEntry, newEntry); |
| | | if (authNDN == null) |
| | | { |
| | | authNDN = conn.getAuthenticationInfo().getAuthenticationDN(); |
| | | try |
| | | { |
| | | StringBuilder builder = new StringBuilder( |
| | | authNDN.toNormalizedString()); |
| | | int oldDNIndex = builder.lastIndexOf(oldDNString); |
| | | builder.replace(oldDNIndex, builder.length(), |
| | | newDNString); |
| | | String newAuthNDNString = builder.toString(); |
| | | newAuthNDN = DN.decode(newAuthNDNString); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // Shouldnt happen. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | } |
| | | } |
| | | if (authZDN == null) |
| | | { |
| | | authZDN = conn.getAuthenticationInfo().getAuthorizationDN(); |
| | | try |
| | | { |
| | | StringBuilder builder = new StringBuilder( |
| | | authZDN.toNormalizedString()); |
| | | int oldDNIndex = builder.lastIndexOf(oldDNString); |
| | | builder.replace(oldDNIndex, builder.length(), |
| | | newDNString); |
| | | String newAuthZDNString = builder.toString(); |
| | | newAuthZDN = DN.decode(newAuthZDNString); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // Shouldnt happen. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | } |
| | | } |
| | | if ((newAuthNDN != null) && (authNDN != null) && |
| | | authNDN.isDescendantOf(oldEntry.getDN())) |
| | | { |
| | | if (newAuthNSet == null) |
| | | { |
| | | newAuthNSet = new CopyOnWriteArraySet<ClientConnection>(); |
| | | } |
| | | conn.getAuthenticationInfo().setAuthenticationDN(newAuthNDN); |
| | | newAuthNSet.add(conn); |
| | | } |
| | | if ((newAuthZDN != null) && (authZDN != null) && |
| | | authZDN.isDescendantOf(oldEntry.getDN())) |
| | | { |
| | | if (newAuthZSet == null) |
| | | { |
| | | newAuthZSet = new CopyOnWriteArraySet<ClientConnection>(); |
| | | } |
| | | conn.getAuthenticationInfo().setAuthorizationDN(newAuthZDN); |
| | | newAuthZSet.add(conn); |
| | | } |
| | | } |
| | | if ((newAuthNDN != null) && (newAuthNSet != null)) |
| | | { |
| | | userMap.put(newAuthNDN, newAuthNSet); |
| | | } |
| | | if ((newAuthZDN != null) && (newAuthZSet != null)) |
| | | { |
| | | userMap.put(newAuthZDN, newAuthZSet); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2007-2008 Sun Microsystems, Inc. |
| | | * Copyright 2007-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | import java.lang.reflect.Method; |
| | | import java.util.*; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.locks.ReentrantReadWriteLock; |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.admin.ClassPropertyDefinition; |
| | |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.BackendInitializationListener; |
| | | import org.opends.server.api.ChangeNotificationListener; |
| | | import org.opends.server.api.DITCacheMap; |
| | | import org.opends.server.api.Group; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | |
| | | 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.InitializationException; |
| | | import org.opends.server.types.ResultCode; |
| | |
| | | |
| | | //Used by group instances to determine if new groups have been |
| | | //registered or groups deleted. |
| | | private long refreshToken=0; |
| | | private volatile long refreshToken=0; |
| | | |
| | | |
| | | // A mapping between the DNs of the config entries and the associated |
| | |
| | | |
| | | // A mapping between the DNs of all group entries and the corresponding |
| | | // group instances. |
| | | private ConcurrentHashMap<DN,Group> groupInstances; |
| | | private DITCacheMap<Group> groupInstances; |
| | | |
| | | // Lock to protect internal data structures. |
| | | private final ReentrantReadWriteLock lock; |
| | | |
| | | |
| | | |
| | |
| | | public GroupManager() |
| | | { |
| | | groupImplementations = new ConcurrentHashMap<DN,Group>(); |
| | | groupInstances = new ConcurrentHashMap<DN,Group>(); |
| | | groupInstances = new DITCacheMap<Group>(); |
| | | |
| | | lock = new ReentrantReadWriteLock(); |
| | | |
| | | DirectoryServer.registerBackendInitializationListener(this); |
| | | DirectoryServer.registerChangeNotificationListener(this); |
| | |
| | | Group group = groupImplementations.remove(configuration.dn()); |
| | | if (group != null) |
| | | { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Iterator<Group> iterator = groupInstances.values().iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | |
| | | group.finalizeGroupImplementation(); |
| | | } |
| | |
| | | Group group = groupImplementations.remove(configuration.dn()); |
| | | if (group != null) |
| | | { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Iterator<Group> iterator = groupInstances.values().iterator(); |
| | | while (iterator.hasNext()) |
| | | { |
| | |
| | | iterator.remove(); |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | |
| | | group.finalizeGroupImplementation(); |
| | | } |
| | |
| | | */ |
| | | public Iterable<Group> getGroupInstances() |
| | | { |
| | | return groupInstances.values(); |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | // Return a copy to protect from structural changes. |
| | | ArrayList<Group> values = new ArrayList<Group>(); |
| | | values.addAll(groupInstances.values()); |
| | | return values; |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | public Group getGroupInstance(DN entryDN) |
| | | { |
| | | Group group = groupInstances.get(entryDN); |
| | | Group group = null; |
| | | |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | group = groupInstances.get(entryDN); |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | |
| | | if (group == null) |
| | | { |
| | | // FIXME -- Should we try to retrieve the corresponding entry and see if |
| | |
| | | continue; |
| | | } |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | for (SearchResultEntry entry : internalSearch.getSearchEntries()) |
| | | { |
| | | try |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | public void performBackendFinalizationProcessing(Backend backend) |
| | | { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Iterator<Map.Entry<DN,Group>> iterator = |
| | | groupInstances.entrySet().iterator(); |
| | | while (iterator.hasNext()) |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | } |
| | | synchronized (groupInstances) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | createAndRegisterGroup(entry); |
| | | refreshToken++; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | } |
| | | synchronized (groupInstances) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | groupInstances.remove(entry.getDN()); |
| | | groupInstances.removeSubtree(entry.getDN(), null); |
| | | refreshToken++; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | if (groupInstances.containsKey(oldEntry.getDN())) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | synchronized (groupInstances) |
| | | if (groupInstances.containsKey(oldEntry.getDN())) |
| | | { |
| | | if (! oldEntry.getDN().equals(newEntry.getDN())) |
| | | { |
| | | // This should never happen, but check for it anyway. |
| | | groupInstances.remove(oldEntry.getDN()); |
| | | } |
| | | |
| | | createAndRegisterGroup(newEntry); |
| | | refreshToken++; |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | if (groupInstances.containsKey(oldEntry.getDN())) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | synchronized (groupInstances) |
| | | Set<Group> groupSet = new HashSet<Group>(); |
| | | groupInstances.removeSubtree(oldEntry.getDN(), groupSet); |
| | | String oldDNString = oldEntry.getDN().toNormalizedString(); |
| | | String newDNString = newEntry.getDN().toNormalizedString(); |
| | | for (Group group : groupSet) |
| | | { |
| | | createAndRegisterGroup(newEntry); |
| | | groupInstances.remove(oldEntry.getDN()); |
| | | StringBuilder builder = new StringBuilder( |
| | | group.getGroupDN().toNormalizedString()); |
| | | int oldDNIndex = builder.lastIndexOf(oldDNString); |
| | | builder.replace(oldDNIndex, builder.length(), |
| | | newDNString); |
| | | String groupDNString = builder.toString(); |
| | | DN groupDN = DN.NULL_DN; |
| | | try |
| | | { |
| | | groupDN = DN.decode(groupDNString); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | // Should not happen but if it does all we |
| | | // can do here is debug log it and continue. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, de); |
| | | } |
| | | continue; |
| | | } |
| | | group.setGroupDN(groupDN); |
| | | groupInstances.put(groupDN, group); |
| | | } |
| | | refreshToken++; |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | |
| | | if (groupImplementation.isGroupDefinition(entry)) |
| | | { |
| | | Group groupInstance = groupImplementation.newInstance(entry); |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | groupInstances.put(entry.getDN(), groupInstance); |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | */ |
| | | void deregisterAllGroups() |
| | | { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | groupInstances.clear(); |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | private DirectoryServerPlugin[] searchResultEntryPlugins; |
| | | private DirectoryServerPlugin[] searchResultReferencePlugins; |
| | | private DirectoryServerPlugin[] subordinateModifyDNPlugins; |
| | | private DirectoryServerPlugin[] subordinateDeletePlugins; |
| | | private DirectoryServerPlugin[] intermediateResponsePlugins; |
| | | |
| | | |
| | |
| | | searchResultEntryPlugins = new DirectoryServerPlugin[0]; |
| | | searchResultReferencePlugins = new DirectoryServerPlugin[0]; |
| | | subordinateModifyDNPlugins = new DirectoryServerPlugin[0]; |
| | | subordinateDeletePlugins = new DirectoryServerPlugin[0]; |
| | | intermediateResponsePlugins = new DirectoryServerPlugin[0]; |
| | | registeredPlugins = |
| | | new ConcurrentHashMap<DN, |
| | |
| | | case SEARCHRESULTENTRY: return PluginType.SEARCH_RESULT_ENTRY; |
| | | case SEARCHRESULTREFERENCE: return PluginType.SEARCH_RESULT_REFERENCE; |
| | | case SUBORDINATEMODIFYDN: return PluginType.SUBORDINATE_MODIFY_DN; |
| | | case SUBORDINATEDELETE: return PluginType.SUBORDINATE_DELETE; |
| | | case INTERMEDIATERESPONSE: return PluginType.INTERMEDIATE_RESPONSE; |
| | | case POSTSYNCHRONIZATIONADD: |
| | | return PluginType.POST_SYNCHRONIZATION_ADD; |
| | |
| | | addPlugin(subordinateModifyDNPlugins, plugin, t, |
| | | pluginRootConfig.getPluginOrderSubordinateModifyDN()); |
| | | break; |
| | | case SUBORDINATE_DELETE: |
| | | subordinateDeletePlugins = |
| | | addPlugin(subordinateDeletePlugins, plugin, t, |
| | | pluginRootConfig.getPluginOrderSubordinateDelete()); |
| | | break; |
| | | case INTERMEDIATE_RESPONSE: |
| | | intermediateResponsePlugins = |
| | | addPlugin(intermediateResponsePlugins, plugin, t, |
| | |
| | | subordinateModifyDNPlugins = |
| | | removePlugin(subordinateModifyDNPlugins, plugin); |
| | | break; |
| | | case SUBORDINATE_DELETE: |
| | | subordinateDeletePlugins = |
| | | removePlugin(subordinateDeletePlugins, plugin); |
| | | break; |
| | | case INTERMEDIATE_RESPONSE: |
| | | intermediateResponsePlugins = |
| | | removePlugin(intermediateResponsePlugins, plugin); |
| | |
| | | |
| | | |
| | | /** |
| | | * Invokes the set of subordinate delete plugins that have been configured |
| | | * in the Directory Server. |
| | | * |
| | | * @param deleteOperation The delete operation with which the |
| | | * subordinate entry is associated. |
| | | * @param entry The subordinate entry being deleted. |
| | | * |
| | | * @return The result of processing the subordinate delete plugins. |
| | | */ |
| | | public PluginResult.SubordinateDelete invokeSubordinateDeletePlugins( |
| | | DeleteOperation deleteOperation, Entry entry) |
| | | { |
| | | PluginResult.SubordinateDelete result = null; |
| | | |
| | | for (DirectoryServerPlugin p : subordinateDeletePlugins) |
| | | { |
| | | if (deleteOperation.isInternalOperation() && |
| | | (! p.invokeForInternalOperations())) |
| | | { |
| | | continue; |
| | | } |
| | | |
| | | try |
| | | { |
| | | DirectoryServerPlugin<? extends PluginCfg> gp = |
| | | (DirectoryServerPlugin<? extends PluginCfg>) p; |
| | | result = gp.processSubordinateDelete(deleteOperation, entry); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | Message message = |
| | | ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_EXCEPTION.get( |
| | | String.valueOf(p.getPluginEntryDN()), |
| | | deleteOperation.getConnectionID(), |
| | | deleteOperation.getOperationID(), |
| | | stackTraceToSingleLineString(e)); |
| | | logError(message); |
| | | |
| | | return PluginResult.SubordinateDelete.stopProcessing( |
| | | DirectoryServer.getServerErrorResultCode(), message); |
| | | } |
| | | |
| | | if (result == null) |
| | | { |
| | | Message message = |
| | | ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_RETURNED_NULL.get( |
| | | String.valueOf(p.getPluginEntryDN()), |
| | | deleteOperation.getConnectionID(), |
| | | String.valueOf(deleteOperation.getOperationID())); |
| | | logError(message); |
| | | |
| | | return PluginResult.SubordinateDelete.stopProcessing( |
| | | DirectoryServer.getServerErrorResultCode(), message); |
| | | } |
| | | else if (! result.continuePluginProcessing()) |
| | | { |
| | | return result; |
| | | } |
| | | } |
| | | |
| | | if (result == null) |
| | | { |
| | | // This should only happen if there were no subordinate modify DN plugins |
| | | // registered, which is fine. |
| | | result = PluginResult.SubordinateDelete.continueOperationProcessing(); |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Invokes the set of intermediate response plugins that have been configured |
| | | * in the Directory Server. |
| | | * |
| | |
| | | |
| | | import org.opends.server.api.Backend; |
| | | import org.opends.server.api.BackendInitializationListener; |
| | | import org.opends.server.api.DITCacheMap; |
| | | import org.opends.server.api.SubentryChangeListener; |
| | | import org.opends.server.api.plugin.InternalDirectoryServerPlugin; |
| | | import org.opends.server.api.plugin.PluginResult; |
| | |
| | | // A mapping between the DNs and applicable collective subentries. |
| | | private HashMap<DN,List<SubEntry>> dn2CollectiveSubEntry; |
| | | |
| | | // A mapping between subentry DNs and subentry objects. |
| | | private DITCacheMap<SubEntry> dit2SubEntry; |
| | | |
| | | // Internal search all operational attributes. |
| | | private LinkedHashSet<String> requestAttrs; |
| | | |
| | |
| | | |
| | | dn2SubEntry = new HashMap<DN,List<SubEntry>>(); |
| | | dn2CollectiveSubEntry = new HashMap<DN,List<SubEntry>>(); |
| | | dit2SubEntry = new DITCacheMap<SubEntry>(); |
| | | |
| | | changeListeners = |
| | | new CopyOnWriteArrayList<SubentryChangeListener>(); |
| | |
| | | dn2SubEntry.put(subDN, subList); |
| | | } |
| | | } |
| | | dit2SubEntry.put(entry.getDN(), subEntry); |
| | | subList.add(subEntry); |
| | | } |
| | | finally |
| | |
| | | SubEntry subEntry = listIterator.next(); |
| | | if (subEntry.getDN().equals(entry.getDN())) |
| | | { |
| | | dit2SubEntry.remove(entry.getDN()); |
| | | listIterator.remove(); |
| | | removed = true; |
| | | break; |
| | |
| | | SubEntry subEntry = listIterator.next(); |
| | | if (subEntry.getDN().equals(entry.getDN())) |
| | | { |
| | | dit2SubEntry.remove(entry.getDN()); |
| | | listIterator.remove(); |
| | | removed = true; |
| | | break; |
| | |
| | | SubEntry subEntry = listIterator.next(); |
| | | if (backend.handlesEntry(subEntry.getDN())) |
| | | { |
| | | dit2SubEntry.remove(subEntry.getDN()); |
| | | listIterator.remove(); |
| | | |
| | | // Notify change listeners. |
| | |
| | | SubEntry subEntry = listIterator.next(); |
| | | if (backend.handlesEntry(subEntry.getDN())) |
| | | { |
| | | dit2SubEntry.remove(subEntry.getDN()); |
| | | listIterator.remove(); |
| | | |
| | | // Notify change listeners. |
| | |
| | | { |
| | | if (entry.isSubentry() || entry.isLDAPSubentry()) |
| | | { |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | try |
| | | { |
| | | addSubEntry(entry); |
| | |
| | | // FIXME -- Handle this. |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void doPostDelete(Entry entry) |
| | | { |
| | | if (entry.isSubentry() || entry.isLDAPSubentry()) |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | removeSubEntry(entry); |
| | | for (SubEntry subEntry : dit2SubEntry.getSubtree(entry.getDN())) |
| | | { |
| | | removeSubEntry(subEntry.getEntry()); |
| | | |
| | | // Notify change listeners. |
| | | for (SubentryChangeListener changeListener : |
| | |
| | | { |
| | | try |
| | | { |
| | | changeListener.handleSubentryDelete(entry); |
| | | changeListener.handleSubentryDelete(subEntry.getEntry()); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | private void doPostModify(Entry oldEntry, Entry newEntry) |
| | | { |
| | | boolean notify = false; |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry()) |
| | | { |
| | | removeSubEntry(oldEntry); |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | private void doPostModifyDN(Entry oldEntry, Entry newEntry) |
| | | { |
| | | if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry()) |
| | | { |
| | | removeSubEntry(oldEntry); |
| | | String oldDNString = oldEntry.getDN().toNormalizedString(); |
| | | String newDNString = newEntry.getDN().toNormalizedString(); |
| | | |
| | | lock.writeLock().lock(); |
| | | try |
| | | { |
| | | Collection<SubEntry> setToDelete = |
| | | dit2SubEntry.getSubtree(oldEntry.getDN()); |
| | | for (SubEntry subentry : setToDelete) |
| | | { |
| | | removeSubEntry(subentry.getEntry()); |
| | | oldEntry = subentry.getEntry(); |
| | | try |
| | | { |
| | | StringBuilder builder = new StringBuilder( |
| | | subentry.getEntry().getDN().toNormalizedString()); |
| | | int oldDNIndex = builder.lastIndexOf(oldDNString); |
| | | builder.replace(oldDNIndex, builder.length(), |
| | | newDNString); |
| | | String subentryDNString = builder.toString(); |
| | | newEntry = subentry.getEntry().duplicate(false); |
| | | newEntry.setDN(DN.decode(subentryDNString)); |
| | | addSubEntry(newEntry); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // Shouldnt happen. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | // FIXME -- Handle this. |
| | | } |
| | | |
| | | // Notify change listeners. |
| | |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.writeLock().unlock(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | |
| | | { |
| | | Entry entry = deleteOperation.getEntryToDelete(); |
| | | |
| | | if (entry.isSubentry() || entry.isLDAPSubentry()) |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | for (SubEntry subEntry : dit2SubEntry.getSubtree(entry.getDN())) |
| | | { |
| | | for (SubentryChangeListener changeListener : |
| | | changeListeners) |
| | | { |
| | | try |
| | | { |
| | | changeListener.checkSubentryDeleteAcceptable(entry); |
| | | changeListener.checkSubentryDeleteAcceptable( |
| | | subEntry.getEntry()); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | |
| | | return PluginResult.PreOperation.continueOperationProcessing(); |
| | | } |
| | |
| | | { |
| | | Entry oldEntry = modifyDNOperation.getOriginalEntry(); |
| | | Entry newEntry = modifyDNOperation.getUpdatedEntry(); |
| | | String oldDNString = oldEntry.getDN().toNormalizedString(); |
| | | String newDNString = newEntry.getDN().toNormalizedString(); |
| | | |
| | | if (oldEntry.isSubentry() || oldEntry.isLDAPSubentry()) |
| | | lock.readLock().lock(); |
| | | try |
| | | { |
| | | Collection<SubEntry> setToDelete = |
| | | dit2SubEntry.getSubtree(oldEntry.getDN()); |
| | | for (SubEntry subentry : setToDelete) |
| | | { |
| | | oldEntry = subentry.getEntry(); |
| | | try |
| | | { |
| | | StringBuilder builder = new StringBuilder( |
| | | subentry.getEntry().getDN().toNormalizedString()); |
| | | int oldDNIndex = builder.lastIndexOf(oldDNString); |
| | | builder.replace(oldDNIndex, builder.length(), |
| | | newDNString); |
| | | String subentryDNString = builder.toString(); |
| | | newEntry = subentry.getEntry().duplicate(false); |
| | | newEntry.setDN(DN.decode(subentryDNString)); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | // Shouldnt happen. |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | } |
| | | for (SubentryChangeListener changeListener : |
| | | changeListeners) |
| | | { |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | lock.readLock().unlock(); |
| | | } |
| | | |
| | | return PluginResult.PreOperation.continueOperationProcessing(); |
| | | } |
| | |
| | | RDN srcRDN = entry.getDN().getRDN(); |
| | | |
| | | // Only process the entry if it has the expected form of RDN. |
| | | // FIXME: Technically it is possible to perform a subtree in |
| | | // this case however such subtree delete would essentially be |
| | | // removing configuration branches which should not happen. |
| | | if (!srcRDN.isMultiValued() && |
| | | srcRDN.getAttributeType(0).equals(attrAlias)) |
| | | { |
| | |
| | | Entry newEntry) |
| | | { |
| | | // No implementation required. |
| | | // FIXME: Technically it is possible to perform a subtree modDN |
| | | // in this case however such subtree modDN would essentially be |
| | | // moving configuration branches which should not happen. |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void setGroupDN(DN groupDN) |
| | | { |
| | | groupEntryDN = groupDN; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the set of member URLs for this dynamic group. The returned set |
| | | * must not be altered by the caller. |
| | | * |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void setGroupDN(DN groupDN) |
| | | { |
| | | groupEntryDN = groupDN; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override() |
| | | public boolean supportsNestedGroups() |
| | | { |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void setGroupDN(DN groupDN) |
| | | { |
| | | groupEntryDN = groupDN; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the DN of the target group for this virtual static group. |
| | | * |
| | | * @return The DN of the target group for this virtual static group. |
| | |
| | | import java.io.FileWriter; |
| | | import java.io.IOException; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.HashSet; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.LinkedHashSet; |
| | |
| | | import org.opends.server.api.ServerShutdownListener; |
| | | import org.opends.server.api.plugin.*; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DeleteOperation; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | |
| | | */ |
| | | public static final String MODIFYDN_DNS="modifyDNs"; |
| | | |
| | | /** |
| | | * Used to save a set in the delete operation attachment map that |
| | | * holds the subordinate entry DNs related to a delete operation. |
| | | */ |
| | | public static final String DELETE_DNS="deleteDNs"; |
| | | |
| | | //The buffered reader that is used to read the log file by the background |
| | | //thread. |
| | | private BufferedReader reader; |
| | |
| | | case POST_OPERATION_DELETE: |
| | | case POST_OPERATION_MODIFY_DN: |
| | | case SUBORDINATE_MODIFY_DN: |
| | | case SUBORDINATE_DELETE: |
| | | // These are acceptable. |
| | | break; |
| | | |
| | |
| | | case POSTOPERATIONDELETE: |
| | | case POSTOPERATIONMODIFYDN: |
| | | case SUBORDINATEMODIFYDN: |
| | | case SUBORDINATEDELETE: |
| | | // These are acceptable. |
| | | break; |
| | | default: |
| | |
| | | return PluginResult.PostOperation.continueOperationProcessing(); |
| | | } |
| | | |
| | | if (modifyDNOperation.getNewSuperior() == null) |
| | | { |
| | | // The entry was simply renamed below the same parent. |
| | | DN oldEntryDN=modifyDNOperation.getOriginalEntry().getDN(); |
| | | DN newEntryDN=modifyDNOperation.getUpdatedEntry().getDN(); |
| | | Map<DN,DN> modDNmap=new LinkedHashMap<DN,DN>(); |
| | | modDNmap.put(oldEntryDN, newEntryDN); |
| | | processModifyDN(modDNmap,(interval != 0)); |
| | | } |
| | | else |
| | | { |
| | | // The entry was moved below a new parent. Use the saved map of old DNs |
| | | // and new DNs from the operation attachment. |
| | | Map<DN,DN> modDNmap = |
| | | (Map<DN, DN>) modifyDNOperation.getAttachment(MODIFYDN_DNS); |
| | | processModifyDN(modDNmap, (interval != 0)); |
| | | if(modDNmap == null) |
| | | { |
| | | modDNmap=new LinkedHashMap<DN,DN>(); |
| | | modifyDNOperation.setAttachment(MODIFYDN_DNS, modDNmap); |
| | | } |
| | | DN oldEntryDN=modifyDNOperation.getOriginalEntry().getDN(); |
| | | DN newEntryDN=modifyDNOperation.getUpdatedEntry().getDN(); |
| | | modDNmap.put(oldEntryDN, newEntryDN); |
| | | |
| | | processModifyDN(modDNmap, (interval != 0)); |
| | | |
| | | return PluginResult.PostOperation.continueOperationProcessing(); |
| | | } |
| | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public PluginResult.PostOperation doPostOperation( |
| | | PostOperationDeleteOperation deleteOperation) |
| | | { |
| | |
| | | return PluginResult.PostOperation.continueOperationProcessing(); |
| | | } |
| | | |
| | | processDelete(deleteOperation.getEntryDN(), (interval != 0)); |
| | | Set<DN> deleteDNset = |
| | | (Set<DN>) deleteOperation.getAttachment(DELETE_DNS); |
| | | if(deleteDNset == null) |
| | | { |
| | | deleteDNset = new HashSet<DN>(); |
| | | deleteOperation.setAttachment(MODIFYDN_DNS, deleteDNset); |
| | | } |
| | | deleteDNset.add(deleteOperation.getEntryDN()); |
| | | |
| | | processDelete(deleteDNset, (interval != 0)); |
| | | return PluginResult.PostOperation.continueOperationProcessing(); |
| | | } |
| | | |
| | |
| | | return PluginResult.SubordinateModifyDN.continueOperationProcessing(); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @SuppressWarnings("unchecked") |
| | | public PluginResult.SubordinateDelete processSubordinateDelete( |
| | | DeleteOperation deleteOperation, Entry entry) |
| | | { |
| | | // This cast gives an unchecked cast warning, suppress it |
| | | // since the cast is ok. |
| | | Set<DN> deleteDNset = |
| | | (Set<DN>) deleteOperation.getAttachment(DELETE_DNS); |
| | | if(deleteDNset == null) |
| | | { |
| | | // First time through, create the set and set it in |
| | | // the operation attachment. |
| | | deleteDNset = new HashSet<DN>(); |
| | | deleteOperation.setAttachment(DELETE_DNS, deleteDNset); |
| | | } |
| | | deleteDNset.add(entry.getDN()); |
| | | return PluginResult.SubordinateDelete.continueOperationProcessing(); |
| | | } |
| | | |
| | | /** |
| | | * Verify that the specified attribute has either a distinguished name syntax |
| | |
| | | * a later time. |
| | | * |
| | | */ |
| | | private void processDelete(DN entryDN, boolean log) |
| | | private void processDelete(Set<DN> deleteDNset, boolean log) |
| | | { |
| | | if(log) |
| | | { |
| | | writeLog(entryDN); |
| | | writeLog(deleteDNset); |
| | | } |
| | | else |
| | | { |
| | | for(DN baseDN : getBaseDNsToSearch()) |
| | | { |
| | | searchBaseDN(baseDN, entryDN, null); |
| | | doBaseDN(baseDN, deleteDNset); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * This method is used in foreground processing of a delete operation. |
| | | * It uses the specified set to perform base DN searching for each |
| | | * element. |
| | | * |
| | | * @param baseDN The DN to base the search at. |
| | | * |
| | | * @param deleteDNset The set containing the delete DNs. |
| | | * |
| | | */ |
| | | private void doBaseDN(DN baseDN, Set<DN> deleteDNset) |
| | | { |
| | | for(DN deletedEntryDN : deleteDNset) |
| | | { |
| | | searchBaseDN(baseDN, deletedEntryDN, null); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * For each attribute type, delete the specified old entry DN and |
| | | * optionally add the specified new entry DN if the DN is not null. |
| | | * The specified entry is used to see if it contains each attribute type so |
| | |
| | | } |
| | | |
| | | /** |
| | | * Write the specified entry DN to the log file. This entry DN is related to |
| | | * a delete operation. |
| | | * Write the specified entry DNs to the log file. |
| | | * These entry DNs are related to a delete operation. |
| | | * |
| | | * @param deletedEntryDN The DN of the deleted entry. |
| | | * |
| | | */ |
| | | private void writeLog(DN deletedEntryDN) { |
| | | synchronized(logFile) { |
| | | try { |
| | | private void writeLog(Set<DN> deleteDNset) { |
| | | synchronized(logFile) |
| | | { |
| | | try |
| | | { |
| | | setupWriter(); |
| | | for (DN deletedEntryDN : deleteDNset) |
| | | { |
| | | writer.write(deletedEntryDN.toNormalizedString()); |
| | | writer.newLine(); |
| | | } |
| | | writer.flush(); |
| | | writer.close(); |
| | | } |
| | |
| | | DN origDn = DN.decode(a[0]); |
| | | //If there is only a single DN string than it must be a delete. |
| | | if(a.length == 1) { |
| | | processDelete(origDn, false); |
| | | processDelete(Collections.singleton(origDn), false); |
| | | } else { |
| | | DN movedDN=DN.decode(a[1]); |
| | | processModifyDN(origDn, movedDN); |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.types; |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the DN of the user as whom the client is authenticated, |
| | | * does nothing if the client is unauthenticated. |
| | | * |
| | | * @param dn authentication identity DN. |
| | | */ |
| | | public void setAuthenticationDN(DN dn) |
| | | { |
| | | if (authenticationEntry == null) |
| | | { |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | authenticationEntry.setDN(dn); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the entry for the user that should be used as the |
| | | * default authorization identity. |
| | | * |
| | |
| | | |
| | | |
| | | /** |
| | | * Sets the DN for the user that should be used as the default |
| | | * authorization identity, does nothing if the client is |
| | | * unauthorized. |
| | | * |
| | | * @param dn authorization identity DN. |
| | | */ |
| | | public void setAuthorizationDN(DN dn) |
| | | { |
| | | if (authorizationEntry == null) |
| | | { |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | authorizationEntry.setDN(dn); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Retrieves the bind DN that the client used for simple |
| | | * authentication. |
| | | * |
| | |
| | | * @return A string representation of this authentication info |
| | | * structure. |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| New file |
| | |
| | | /* |
| | | * 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 2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.HashMap; |
| | | import java.util.HashSet; |
| | | import java.util.Iterator; |
| | | import java.util.Map; |
| | | import java.util.Map.Entry; |
| | | import java.util.Set; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.testng.annotations.BeforeClass; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | /** |
| | | * A set of basic test cases for DITCacheMap class. |
| | | */ |
| | | public class DITCacheMapTestCase extends APITestCase |
| | | { |
| | | private static final DITCacheMap<String> ditMap = |
| | | new DITCacheMap<String>(); |
| | | |
| | | private static final String dn0String = |
| | | "cn=Object0,dc=example,dc=com"; |
| | | private static final String dn1String = |
| | | "cn=Object1,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn2String = |
| | | "cn=Object2,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn3String = |
| | | "cn=Object3,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn4String = |
| | | "cn=Object4,ou=Classes,dc=example,dc=com"; |
| | | private static final String dn5String = |
| | | "cn=Object5,ou=Classes,dc=example,dc=com"; |
| | | private static final String dn6String = |
| | | "cn=Object6,ou=More,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn7String = |
| | | "cn=Object7,ou=More,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn8String = |
| | | "cn=Object8,ou=More,ou=Objects,dc=example,dc=com"; |
| | | private static final String dn9String = |
| | | "cn=Object9,ou=No,ou=More,ou=Objects,dc=example,dc=com"; |
| | | |
| | | private static DN dn0; |
| | | private static DN dn1; |
| | | private static DN dn2; |
| | | private static DN dn3; |
| | | private static DN dn4; |
| | | private static DN dn5; |
| | | private static DN dn6; |
| | | private static DN dn7; |
| | | private static DN dn8; |
| | | private static DN dn9; |
| | | |
| | | private void putAllAndVerify() |
| | | { |
| | | Map<DN,String> hashMap = |
| | | new HashMap<DN,String>(); |
| | | |
| | | hashMap.put(dn0, dn0String); |
| | | hashMap.put(dn1, dn1String); |
| | | hashMap.put(dn2, dn2String); |
| | | hashMap.put(dn3, dn3String); |
| | | hashMap.put(dn4, dn4String); |
| | | hashMap.put(dn5, dn5String); |
| | | hashMap.put(dn6, dn6String); |
| | | hashMap.put(dn7, dn7String); |
| | | hashMap.put(dn8, dn8String); |
| | | hashMap.put(dn9, dn9String); |
| | | |
| | | ditMap.putAll(hashMap); |
| | | |
| | | assertFalse(ditMap.isEmpty()); |
| | | assertEquals(ditMap.size(), 10); |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | assertTrue(ditMap.containsKey(dn6)); |
| | | assertTrue(ditMap.containsKey(dn7)); |
| | | assertTrue(ditMap.containsKey(dn8)); |
| | | assertTrue(ditMap.containsKey(dn9)); |
| | | assertTrue(ditMap.containsValue(dn0String)); |
| | | assertTrue(ditMap.containsValue(dn1String)); |
| | | assertTrue(ditMap.containsValue(dn2String)); |
| | | assertTrue(ditMap.containsValue(dn3String)); |
| | | assertTrue(ditMap.containsValue(dn4String)); |
| | | assertTrue(ditMap.containsValue(dn5String)); |
| | | assertTrue(ditMap.containsValue(dn6String)); |
| | | assertTrue(ditMap.containsValue(dn7String)); |
| | | assertTrue(ditMap.containsValue(dn8String)); |
| | | assertTrue(ditMap.containsValue(dn9String)); |
| | | } |
| | | |
| | | private void clearTestMap() |
| | | { |
| | | ditMap.clear(); |
| | | assertTrue(ditMap.isEmpty()); |
| | | assertEquals(ditMap.size(), 0); |
| | | } |
| | | |
| | | @BeforeClass() |
| | | public void beforeClass() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | | dn0 = DN.decode(dn0String); |
| | | dn1 = DN.decode(dn1String); |
| | | dn2 = DN.decode(dn2String); |
| | | dn3 = DN.decode(dn3String); |
| | | dn4 = DN.decode(dn4String); |
| | | dn5 = DN.decode(dn5String); |
| | | dn6 = DN.decode(dn6String); |
| | | dn7 = DN.decode(dn7String); |
| | | dn8 = DN.decode(dn8String); |
| | | dn9 = DN.decode(dn9String); |
| | | } |
| | | |
| | | @Test() |
| | | public void testDITCacheMapBasicOps() |
| | | throws Exception |
| | | { |
| | | clearTestMap(); |
| | | |
| | | ditMap.put(dn0, dn0String); |
| | | ditMap.put(dn1, dn1String); |
| | | ditMap.put(dn2, dn2String); |
| | | ditMap.put(dn3, dn3String); |
| | | ditMap.put(dn4, dn4String); |
| | | ditMap.put(dn5, dn5String); |
| | | ditMap.put(dn6, dn6String); |
| | | ditMap.put(dn7, dn7String); |
| | | ditMap.put(dn8, dn8String); |
| | | ditMap.put(dn9, dn9String); |
| | | |
| | | assertFalse(ditMap.isEmpty()); |
| | | assertEquals(ditMap.size(), 10); |
| | | |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | assertTrue(ditMap.containsKey(dn6)); |
| | | assertTrue(ditMap.containsKey(dn7)); |
| | | assertTrue(ditMap.containsKey(dn8)); |
| | | assertTrue(ditMap.containsKey(dn9)); |
| | | |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "ou=No,ou=More,ou=Objects,dc=example,dc=com"))); |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "ou=More,ou=Objects,dc=example,dc=com"))); |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "ou=Objects,dc=example,dc=com"))); |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "ou=Classes,dc=example,dc=com"))); |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "dc=example,dc=com"))); |
| | | assertFalse(ditMap.containsKey(DN.decode( |
| | | "dc=com"))); |
| | | |
| | | assertTrue(ditMap.containsValue(dn0String)); |
| | | assertTrue(ditMap.containsValue(dn1String)); |
| | | assertTrue(ditMap.containsValue(dn2String)); |
| | | assertTrue(ditMap.containsValue(dn3String)); |
| | | assertTrue(ditMap.containsValue(dn4String)); |
| | | assertTrue(ditMap.containsValue(dn5String)); |
| | | assertTrue(ditMap.containsValue(dn6String)); |
| | | assertTrue(ditMap.containsValue(dn7String)); |
| | | assertTrue(ditMap.containsValue(dn8String)); |
| | | assertTrue(ditMap.containsValue(dn9String)); |
| | | |
| | | assertEquals(ditMap.get(dn0), dn0String); |
| | | assertEquals(ditMap.get(dn1), dn1String); |
| | | assertEquals(ditMap.get(dn2), dn2String); |
| | | assertEquals(ditMap.get(dn3), dn3String); |
| | | assertEquals(ditMap.get(dn4), dn4String); |
| | | assertEquals(ditMap.get(dn5), dn5String); |
| | | assertEquals(ditMap.get(dn6), dn6String); |
| | | assertEquals(ditMap.get(dn7), dn7String); |
| | | assertEquals(ditMap.get(dn8), dn8String); |
| | | assertEquals(ditMap.get(dn9), dn9String); |
| | | |
| | | assertNull(ditMap.get(DN.decode( |
| | | "ou=No,ou=More,ou=Objects,dc=example,dc=com"))); |
| | | assertNull(ditMap.get(DN.decode( |
| | | "ou=More,ou=Objects,dc=example,dc=com"))); |
| | | assertNull(ditMap.get(DN.decode( |
| | | "ou=Objects,dc=example,dc=com"))); |
| | | assertNull(ditMap.get(DN.decode( |
| | | "ou=Classes,dc=example,dc=com"))); |
| | | assertNull(ditMap.get(DN.decode( |
| | | "dc=example,dc=com"))); |
| | | assertNull(ditMap.get(DN.decode( |
| | | "dc=com"))); |
| | | } |
| | | |
| | | @Test() |
| | | public void testDITCacheMapGetSubTree() |
| | | throws Exception |
| | | { |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | Collection<String> subtreeSet = ditMap.getSubtree( |
| | | DN.decode("dc=example,dc=com")); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 10); |
| | | assertTrue(subtreeSet.contains(dn0String)); |
| | | assertTrue(subtreeSet.contains(dn1String)); |
| | | assertTrue(subtreeSet.contains(dn2String)); |
| | | assertTrue(subtreeSet.contains(dn3String)); |
| | | assertTrue(subtreeSet.contains(dn4String)); |
| | | assertTrue(subtreeSet.contains(dn5String)); |
| | | assertTrue(subtreeSet.contains(dn6String)); |
| | | assertTrue(subtreeSet.contains(dn7String)); |
| | | assertTrue(subtreeSet.contains(dn8String)); |
| | | assertTrue(subtreeSet.contains(dn9String)); |
| | | |
| | | subtreeSet = ditMap.getSubtree( |
| | | DN.decode("ou=Objects,dc=example,dc=com")); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 7); |
| | | assertTrue(subtreeSet.contains(dn1String)); |
| | | assertTrue(subtreeSet.contains(dn2String)); |
| | | assertTrue(subtreeSet.contains(dn3String)); |
| | | assertTrue(subtreeSet.contains(dn6String)); |
| | | assertTrue(subtreeSet.contains(dn7String)); |
| | | assertTrue(subtreeSet.contains(dn8String)); |
| | | assertTrue(subtreeSet.contains(dn9String)); |
| | | |
| | | |
| | | subtreeSet = ditMap.getSubtree( |
| | | DN.decode("ou=Classes,dc=example,dc=com")); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 2); |
| | | assertTrue(subtreeSet.contains(dn4String)); |
| | | assertTrue(subtreeSet.contains(dn5String)); |
| | | |
| | | subtreeSet = ditMap.getSubtree( |
| | | DN.decode("ou=More,ou=Objects,dc=example,dc=com")); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 4); |
| | | assertTrue(subtreeSet.contains(dn6String)); |
| | | assertTrue(subtreeSet.contains(dn7String)); |
| | | assertTrue(subtreeSet.contains(dn8String)); |
| | | assertTrue(subtreeSet.contains(dn9String)); |
| | | |
| | | subtreeSet = ditMap.getSubtree( |
| | | DN.decode("ou=No,ou=More,ou=Objects,dc=example,dc=com")); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 1); |
| | | assertTrue(subtreeSet.contains(dn9String)); |
| | | |
| | | subtreeSet = ditMap.getSubtree(dn0); |
| | | assertFalse(subtreeSet.isEmpty()); |
| | | assertEquals(subtreeSet.size(), 1); |
| | | assertTrue(subtreeSet.contains(dn0String)); |
| | | } |
| | | |
| | | @Test() |
| | | public void testDITCacheMapKeyAndEntrySet() |
| | | throws Exception |
| | | { |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | Set<DN> dnSet = ditMap.keySet(); |
| | | assertFalse(dnSet.isEmpty()); |
| | | assertEquals(dnSet.size(), 10); |
| | | assertTrue(dnSet.contains(dn0)); |
| | | assertTrue(dnSet.contains(dn1)); |
| | | assertTrue(dnSet.contains(dn2)); |
| | | assertTrue(dnSet.contains(dn3)); |
| | | assertTrue(dnSet.contains(dn4)); |
| | | assertTrue(dnSet.contains(dn5)); |
| | | assertTrue(dnSet.contains(dn6)); |
| | | assertTrue(dnSet.contains(dn7)); |
| | | assertTrue(dnSet.contains(dn8)); |
| | | assertTrue(dnSet.contains(dn9)); |
| | | |
| | | Set<Entry<DN,String>> entrySet = ditMap.entrySet(); |
| | | assertFalse(entrySet.isEmpty()); |
| | | assertEquals(entrySet.size(), 10); |
| | | Iterator<Entry<DN,String>> iterator = entrySet.iterator(); |
| | | Map<DN,String> tempMap = new HashMap<DN,String>(); |
| | | while (iterator.hasNext()) |
| | | { |
| | | Entry<DN,String> entry = iterator.next(); |
| | | if ((entry.getKey().equals(dn0) && |
| | | entry.getValue().equals(dn0String)) || |
| | | (entry.getKey().equals(dn1) && |
| | | entry.getValue().equals(dn1String)) || |
| | | (entry.getKey().equals(dn2) && |
| | | entry.getValue().equals(dn2String)) || |
| | | (entry.getKey().equals(dn3) && |
| | | entry.getValue().equals(dn3String)) || |
| | | (entry.getKey().equals(dn4) && |
| | | entry.getValue().equals(dn4String)) || |
| | | (entry.getKey().equals(dn5) && |
| | | entry.getValue().equals(dn5String)) || |
| | | (entry.getKey().equals(dn6) && |
| | | entry.getValue().equals(dn6String)) || |
| | | (entry.getKey().equals(dn7) && |
| | | entry.getValue().equals(dn7String)) || |
| | | (entry.getKey().equals(dn8) && |
| | | entry.getValue().equals(dn8String)) || |
| | | (entry.getKey().equals(dn9) && |
| | | entry.getValue().equals(dn9String))) |
| | | { |
| | | assertFalse(tempMap.containsKey(entry.getKey())); |
| | | assertFalse(tempMap.containsValue(entry.getValue())); |
| | | assertNull(tempMap.put(entry.getKey(), entry.getValue())); |
| | | } |
| | | else |
| | | { |
| | | fail(); |
| | | } |
| | | iterator.remove(); |
| | | } |
| | | assertEquals(tempMap.size(), 10); |
| | | assertEquals(ditMap.size(), 0); |
| | | assertTrue(ditMap.isEmpty()); |
| | | } |
| | | |
| | | @Test() |
| | | public void testDITCacheMapRemoveSubTree() |
| | | throws Exception |
| | | { |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | Set<String> removeSet = new HashSet<String>(); |
| | | assertTrue(ditMap.removeSubtree(DN.decode( |
| | | "dc=example,dc=com"), |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 10); |
| | | assertTrue(removeSet.contains(dn0String)); |
| | | assertTrue(removeSet.contains(dn1String)); |
| | | assertTrue(removeSet.contains(dn2String)); |
| | | assertTrue(removeSet.contains(dn3String)); |
| | | assertTrue(removeSet.contains(dn4String)); |
| | | assertTrue(removeSet.contains(dn5String)); |
| | | assertTrue(removeSet.contains(dn6String)); |
| | | assertTrue(removeSet.contains(dn7String)); |
| | | assertTrue(removeSet.contains(dn8String)); |
| | | assertTrue(removeSet.contains(dn9String)); |
| | | assertTrue(ditMap.isEmpty()); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | removeSet.clear(); |
| | | assertTrue(ditMap.removeSubtree(DN.decode( |
| | | "ou=Objects,dc=example,dc=com"), |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 7); |
| | | assertTrue(removeSet.contains(dn1String)); |
| | | assertTrue(removeSet.contains(dn2String)); |
| | | assertTrue(removeSet.contains(dn3String)); |
| | | assertTrue(removeSet.contains(dn6String)); |
| | | assertTrue(removeSet.contains(dn7String)); |
| | | assertTrue(removeSet.contains(dn8String)); |
| | | assertTrue(removeSet.contains(dn9String)); |
| | | assertEquals(ditMap.size(), 3); |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | removeSet.clear(); |
| | | assertTrue(ditMap.removeSubtree(DN.decode( |
| | | "ou=Classes,dc=example,dc=com"), |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 2); |
| | | assertTrue(removeSet.contains(dn4String)); |
| | | assertTrue(removeSet.contains(dn5String)); |
| | | assertEquals(ditMap.size(), 8); |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn6)); |
| | | assertTrue(ditMap.containsKey(dn7)); |
| | | assertTrue(ditMap.containsKey(dn8)); |
| | | assertTrue(ditMap.containsKey(dn9)); |
| | | |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | removeSet.clear(); |
| | | assertTrue(ditMap.removeSubtree(DN.decode( |
| | | "ou=More,ou=Objects,dc=example,dc=com"), |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 4); |
| | | assertTrue(removeSet.contains(dn6String)); |
| | | assertTrue(removeSet.contains(dn7String)); |
| | | assertTrue(removeSet.contains(dn8String)); |
| | | assertTrue(removeSet.contains(dn9String)); |
| | | assertEquals(ditMap.size(), 6); |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | removeSet.clear(); |
| | | assertTrue(ditMap.removeSubtree(DN.decode( |
| | | "ou=No,ou=More,ou=Objects,dc=example,dc=com"), |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 1); |
| | | assertTrue(removeSet.contains(dn9String)); |
| | | assertEquals(ditMap.size(), 9); |
| | | assertTrue(ditMap.containsKey(dn0)); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | assertTrue(ditMap.containsKey(dn6)); |
| | | assertTrue(ditMap.containsKey(dn7)); |
| | | assertTrue(ditMap.containsKey(dn8)); |
| | | |
| | | clearTestMap(); |
| | | |
| | | putAllAndVerify(); |
| | | |
| | | removeSet.clear(); |
| | | assertTrue(ditMap.removeSubtree(dn0, |
| | | removeSet)); |
| | | assertFalse(removeSet.isEmpty()); |
| | | assertEquals(removeSet.size(), 1); |
| | | assertTrue(removeSet.contains(dn0String)); |
| | | assertEquals(ditMap.size(), 9); |
| | | assertTrue(ditMap.containsKey(dn1)); |
| | | assertTrue(ditMap.containsKey(dn2)); |
| | | assertTrue(ditMap.containsKey(dn3)); |
| | | assertTrue(ditMap.containsKey(dn4)); |
| | | assertTrue(ditMap.containsKey(dn5)); |
| | | assertTrue(ditMap.containsKey(dn6)); |
| | | assertTrue(ditMap.containsKey(dn7)); |
| | | assertTrue(ditMap.containsKey(dn8)); |
| | | assertTrue(ditMap.containsKey(dn9)); |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.api.plugin; |
| | | |
| | |
| | | expectedPublicMethods.add(sigList); |
| | | |
| | | sigList = new LinkedList<String>(); |
| | | sigList.add("processSubordinateDelete"); |
| | | sigList.add("org.opends.server.api.plugin." + |
| | | "PluginResult$SubordinateDelete"); |
| | | sigList.add("org.opends.server.core." + |
| | | "DeleteOperation"); |
| | | sigList.add("org.opends.server.types.Entry"); |
| | | expectedPublicMethods.add(sigList); |
| | | |
| | | sigList = new LinkedList<String>(); |
| | | sigList.add("processIntermediateResponse"); |
| | | sigList.add("org.opends.server.api.plugin." + |
| | | "PluginResult$IntermediateResponse"); |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2009 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | import org.opends.server.tools.LDAPReader; |
| | | import org.opends.server.tools.LDAPWriter; |
| | | import org.opends.server.types.*; |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.tools.LDAPDelete; |
| | | import org.opends.server.tools.LDAPModify; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.opends.server.protocols.ldap.LDAPConstants.*; |
| | | import org.opends.messages.Message; |
| | | |
| | | |
| | | /** |
| | |
| | | |
| | | |
| | | /** |
| | | * Tests to ensure that performing subtree delete will |
| | | * cause the connection to no longer be associated |
| | | * with the previous identity. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(groups = "slow") |
| | | public void testSubtreeDeleteClearsAuthInfo() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.restartServer(); |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | TestCaseUtils.addEntries( |
| | | "dn: ou=people,dc=example,dc=com", |
| | | "objectClass: organizationalUnit", |
| | | "objectClass: top", |
| | | "ou: people", |
| | | "", |
| | | "dn: uid=test,ou=people,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: test", |
| | | "givenName: test", |
| | | "sn: Test", |
| | | "cn: Test", |
| | | "userPassword: password"); |
| | | |
| | | String dnString = "uid=test,ou=people,dc=example,dc=com"; |
| | | DN userDN = DN.decode(dnString); |
| | | |
| | | Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); |
| | | s.setSoTimeout(6000); |
| | | LDAPReader r = new LDAPReader(s); |
| | | LDAPWriter w = new LDAPWriter(s); |
| | | |
| | | BindRequestProtocolOp bindRequest = |
| | | new BindRequestProtocolOp(ByteString.valueOf(dnString), |
| | | 3, ByteString.valueOf("password")); |
| | | LDAPMessage message = new LDAPMessage(1, bindRequest); |
| | | w.writeMessage(message); |
| | | |
| | | message = r.readMessage(); |
| | | BindResponseProtocolOp bindResponse = |
| | | message.getBindResponseProtocolOp(); |
| | | assertEquals(bindResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(DirectoryServer.getAuthenticatedUsers().get( |
| | | userDN)); |
| | | assertEquals(DirectoryServer.getAuthenticatedUsers().get( |
| | | userDN).size(), 1); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-J", OID_SUBTREE_DELETE_CONTROL + ":true", |
| | | "--noPropertiesFile", |
| | | "ou=people,dc=example,dc=com" |
| | | }; |
| | | assertEquals(LDAPDelete.mainDelete(args, false, null, System.err), 0); |
| | | |
| | | assertNull(DirectoryServer.getAuthenticatedUsers().get(userDN)); |
| | | |
| | | s.close(); |
| | | |
| | | // Cleanup. |
| | | TestCaseUtils.clearJEBackend(false, |
| | | "userRoot", "dc=example,dc=com"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests to ensure that performing subtree modify will |
| | | * cause the connection to be associated with new auth |
| | | * identity instead of the previous identity. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(groups = "slow") |
| | | public void testSubtreeModifyUpdatesAuthInfo() |
| | | throws Exception |
| | | { |
| | | TestCaseUtils.restartServer(); |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | TestCaseUtils.addEntries( |
| | | "dn: ou=people,dc=example,dc=com", |
| | | "objectClass: organizationalUnit", |
| | | "objectClass: top", |
| | | "ou: people", |
| | | "", |
| | | "dn: uid=test,ou=people,dc=example,dc=com", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: test", |
| | | "givenName: test", |
| | | "sn: Test", |
| | | "cn: Test", |
| | | "userPassword: password"); |
| | | |
| | | String dnString = "uid=test,ou=people,dc=example,dc=com"; |
| | | DN userDN = DN.decode(dnString); |
| | | |
| | | Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort()); |
| | | s.setSoTimeout(6000); |
| | | LDAPReader r = new LDAPReader(s); |
| | | LDAPWriter w = new LDAPWriter(s); |
| | | |
| | | BindRequestProtocolOp bindRequest = |
| | | new BindRequestProtocolOp(ByteString.valueOf(dnString), |
| | | 3, ByteString.valueOf("password")); |
| | | LDAPMessage message = new LDAPMessage(1, bindRequest); |
| | | w.writeMessage(message); |
| | | |
| | | message = r.readMessage(); |
| | | BindResponseProtocolOp bindResponse = |
| | | message.getBindResponseProtocolOp(); |
| | | assertEquals(bindResponse.getResultCode(), 0); |
| | | |
| | | assertNotNull(DirectoryServer.getAuthenticatedUsers().get( |
| | | userDN)); |
| | | assertEquals(DirectoryServer.getAuthenticatedUsers().get( |
| | | userDN).size(), 1); |
| | | |
| | | String path = TestCaseUtils.createTempFile( |
| | | "dn: ou=people,dc=example,dc=com", |
| | | "changetype: moddn", |
| | | "newRDN: ou=users", |
| | | "deleteOldRDN: 1"); |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "--noPropertiesFile", |
| | | "-f", path |
| | | }; |
| | | assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0); |
| | | |
| | | String newDNString = "uid=test,ou=users,dc=example,dc=com"; |
| | | DN newUserDN = DN.decode(newDNString); |
| | | |
| | | assertNotNull(DirectoryServer.getAuthenticatedUsers().get( |
| | | newUserDN)); |
| | | assertEquals(DirectoryServer.getAuthenticatedUsers().get( |
| | | newUserDN).size(), 1); |
| | | |
| | | s.close(); |
| | | |
| | | // Cleanup. |
| | | TestCaseUtils.clearJEBackend(false, |
| | | "userRoot", "dc=example,dc=com"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests to ensure that the "ignore" password policy state update policy |
| | | * works as expected. |
| | | * |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2008 Sun Microsystems, Inc. |
| | | * Copyright 2008-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.core; |
| | | |
| | |
| | | import org.opends.server.extensions.VirtualStaticGroup; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.tools.LDAPDelete; |
| | | import org.opends.server.tools.LDAPModify; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.Attributes; |
| | | import org.opends.server.types.DereferencePolicy; |
| | |
| | | import org.opends.server.types.SearchFilter; |
| | | import org.opends.server.types.SearchScope; |
| | | |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Tests subtree delete operation on groups tree. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSubtreeDelete() throws Exception { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | GroupManager groupManager = DirectoryServer.getGroupManager(); |
| | | groupManager.deregisterAllGroups(); |
| | | addSubtreeGroupTestEntries(); |
| | | |
| | | Group group1 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=moregroups,dc=example,dc=com")); |
| | | assertNotNull(group1); |
| | | Group group2 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=groups,dc=example,dc=com")); |
| | | assertNotNull(group2); |
| | | Group group3 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group2,ou=groups,dc=example,dc=com")); |
| | | assertNotNull(group3); |
| | | |
| | | // Get a client connection authenticated as user1 and make sure it handles |
| | | // group operations correctly. |
| | | DN userDN = DN.decode("uid=test1,ou=people,dc=example,dc=com"); |
| | | InternalClientConnection conn = new InternalClientConnection(userDN); |
| | | InternalSearchOperation searchOperation = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), null, DN.nullDN(), |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=*)"), null, |
| | | null); |
| | | |
| | | assertTrue(conn.isMemberOf(group1, null)); |
| | | assertTrue(conn.isMemberOf(group2, null)); |
| | | assertTrue(conn.isMemberOf(group3, null)); |
| | | |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-J", OID_SUBTREE_DELETE_CONTROL + ":true", |
| | | "--noPropertiesFile", |
| | | "ou=groups,dc=example,dc=com" |
| | | }; |
| | | assertEquals(LDAPDelete.mainDelete(args, false, null, System.err), 0); |
| | | |
| | | InternalClientConnection conn1 = |
| | | new InternalClientConnection(userDN); |
| | | searchOperation = |
| | | new InternalSearchOperation(conn1, conn1.nextOperationID(), |
| | | conn1.nextMessageID(), null, DN.nullDN(), |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=*)"), null, |
| | | null); |
| | | |
| | | group1 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=moregroups,dc=example,dc=com")); |
| | | assertNotNull(group1); |
| | | assertTrue(conn1.isMemberOf(group1, null)); |
| | | group2 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=groups,dc=example,dc=com")); |
| | | assertNull(group2); |
| | | group3 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group2,ou=groups,dc=example,dc=com")); |
| | | assertNull(group3); |
| | | |
| | | // Cleanup. |
| | | TestCaseUtils.clearJEBackend(false, |
| | | "userRoot", "dc=example,dc=com"); |
| | | } |
| | | |
| | | /** |
| | | * Tests subtree modify operation on groups tree. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test() |
| | | public void testSubtreeModify() throws Exception { |
| | | TestCaseUtils.clearJEBackend(true, "userRoot", "dc=example,dc=com"); |
| | | GroupManager groupManager = DirectoryServer.getGroupManager(); |
| | | groupManager.deregisterAllGroups(); |
| | | addSubtreeGroupTestEntries(); |
| | | |
| | | Group group1 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=moregroups,dc=example,dc=com")); |
| | | assertNotNull(group1); |
| | | Group group2 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=groups,dc=example,dc=com")); |
| | | assertNotNull(group2); |
| | | Group group3 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group2,ou=groups,dc=example,dc=com")); |
| | | assertNotNull(group3); |
| | | |
| | | // Get a client connection authenticated as user1 and make sure it handles |
| | | // group operations correctly. |
| | | DN userDN = DN.decode("uid=test1,ou=people,dc=example,dc=com"); |
| | | InternalClientConnection conn = new InternalClientConnection(userDN); |
| | | InternalSearchOperation searchOperation = |
| | | new InternalSearchOperation(conn, conn.nextOperationID(), |
| | | conn.nextMessageID(), null, DN.nullDN(), |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=*)"), null, |
| | | null); |
| | | |
| | | assertTrue(conn.isMemberOf(group1, null)); |
| | | assertTrue(conn.isMemberOf(group2, null)); |
| | | assertTrue(conn.isMemberOf(group3, null)); |
| | | |
| | | String path = TestCaseUtils.createTempFile( |
| | | "dn: ou=groups,dc=example,dc=com", |
| | | "changetype: moddn", |
| | | "newRDN: ou=newgroups", |
| | | "deleteOldRDN: 1"); |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "--noPropertiesFile", |
| | | "-f", path |
| | | }; |
| | | assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0); |
| | | |
| | | InternalClientConnection conn1 = |
| | | new InternalClientConnection(userDN); |
| | | searchOperation = |
| | | new InternalSearchOperation(conn1, conn1.nextOperationID(), |
| | | conn1.nextMessageID(), null, DN.nullDN(), |
| | | SearchScope.BASE_OBJECT, |
| | | DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, |
| | | SearchFilter.createFilterFromString("(objectClass=*)"), null, |
| | | null); |
| | | |
| | | group1 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=moregroups,dc=example,dc=com")); |
| | | assertNotNull(group1); |
| | | assertTrue(conn1.isMemberOf(group1, null)); |
| | | group2 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=groups,dc=example,dc=com")); |
| | | assertNull(group2); |
| | | group3 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group2,ou=groups,dc=example,dc=com")); |
| | | assertNull(group3); |
| | | Group newGroup2 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group1,ou=newgroups,dc=example,dc=com")); |
| | | assertNotNull(newGroup2); |
| | | assertTrue(conn.isMemberOf(newGroup2, null)); |
| | | Group newGroup3 = groupManager.getGroupInstance( |
| | | DN.decode("cn=group2,ou=newgroups,dc=example,dc=com")); |
| | | assertNotNull(newGroup3); |
| | | assertTrue(conn.isMemberOf(newGroup3, null)); |
| | | |
| | | // Cleanup. |
| | | TestCaseUtils.clearJEBackend(false, |
| | | "userRoot", "dc=example,dc=com"); |
| | | } |
| | | |
| | | /** |
| | | * Adds nested group entries. |
| | | * |
| | | * @throws Exception If a problem adding the entries occurs. |
| | |
| | | "cn: User 5", |
| | | "userPassword: password"); |
| | | } |
| | | |
| | | /** |
| | | * Adds entries for subtree operations tests. |
| | | * |
| | | * @throws Exception If a problem adding the entries occurs. |
| | | */ |
| | | private void addSubtreeGroupTestEntries() throws Exception { |
| | | |
| | | TestCaseUtils.addEntries( |
| | | "dn: ou=people,dc=example,dc=com", |
| | | "objectClass: organizationalUnit", |
| | | "objectClass: top", |
| | | "ou: people", |
| | | "", |
| | | "dn: uid=test1,ou=people,dc=example,dc=com", |
| | | "objectClass: person", |
| | | "objectClass: inetOrgPerson", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: top", |
| | | "uid: test1", |
| | | "cn: test", |
| | | "sn: test", |
| | | "userPassword: password", |
| | | "", |
| | | "dn: ou=groups,dc=example,dc=com", |
| | | "objectClass: organizationalUnit", |
| | | "objectClass: top", |
| | | "ou: groups", |
| | | "", |
| | | "dn: cn=group1,ou=groups,dc=example,dc=com", |
| | | "objectClass: groupOfNames", |
| | | "objectClass: top", |
| | | "member: uid=test1,ou=people,dc=example,dc=com", |
| | | "cn: group1", |
| | | "", |
| | | "dn: cn=group2,ou=groups,dc=example,dc=com", |
| | | "objectClass: groupOfNames", |
| | | "objectClass: top", |
| | | "member: uid=test1,ou=people,dc=example,dc=com", |
| | | "cn: group2", |
| | | "", |
| | | "dn: ou=moregroups,dc=example,dc=com", |
| | | "objectClass: organizationalUnit", |
| | | "objectClass: top", |
| | | "ou: moregroups", |
| | | "", |
| | | "dn: cn=group1,ou=moregroups,dc=example,dc=com", |
| | | "objectClass: groupOfNames", |
| | | "objectClass: top", |
| | | "member: uid=test1,ou=people,dc=example,dc=com", |
| | | "cn: group1" |
| | | ); |
| | | } |
| | | } |
| | | |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.server.core; |
| | |
| | | import org.opends.server.protocols.ldap.LDAPAttribute; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.protocols.ldap.LDAPModification; |
| | | import org.opends.server.tools.LDAPDelete; |
| | | import org.opends.server.tools.LDAPModify; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValues; |
| | | import org.opends.server.types.ByteString; |
| | |
| | | import org.testng.annotations.BeforeMethod; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.opends.server.util.ServerConstants.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | | public class SubentryManagerTestCase extends CoreTestCase |
| | |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | TestCaseUtils.clearJEBackend(false, "userRoot", SUFFIX); |
| | | |
| | | InternalClientConnection connection = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | // Add suffix entry. |
| | | DN suffixDN = DN.decode(SUFFIX); |
| | | if (DirectoryServer.getEntry(suffixDN) == null) |
| | | { |
| | | Entry suffixEntry = StaticUtils.createEntry(suffixDN); |
| | | AddOperation addOperation = |
| | | connection.processAdd(suffixEntry.getDN(), |
| | | suffixEntry.getObjectClasses(), |
| | | suffixEntry.getUserAttributes(), |
| | | suffixEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(suffixEntry.getDN())); |
| | | } |
| | | |
| | | // Add base entry. |
| | | DN baseDN = DN.decode(BASE); |
| | | if (DirectoryServer.getEntry(baseDN) == null) |
| | | { |
| | | Entry baseEntry = StaticUtils.createEntry(baseDN); |
| | | AddOperation addOperation = |
| | | connection.processAdd(baseEntry.getDN(), |
| | | baseEntry.getObjectClasses(), |
| | | baseEntry.getUserAttributes(), |
| | | baseEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(baseEntry.getDN())); |
| | | } |
| | | |
| | | // Add test entry. |
| | | testEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=rogasawara," + BASE, |
| | | "objectclass: top", |
| | | "objectclass: person", |
| | | "objectclass: organizationalPerson", |
| | | "objectclass: inetOrgPerson", |
| | | "uid: rogasawara", |
| | | "userpassword: password", |
| | | "mail: rogasawara@example.com", |
| | | "givenname: Rodney", |
| | | "sn: Ogasawara", |
| | | "cn: Rodney Ogasawara", |
| | | "title: Sales, Director" |
| | | ); |
| | | AddOperation addOperation = |
| | | connection.processAdd(testEntry.getDN(), |
| | | testEntry.getObjectClasses(), |
| | | testEntry.getUserAttributes(), |
| | | testEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(testEntry.getDN())); |
| | | |
| | | // Add test subentry. |
| | | ldapSubentry = TestCaseUtils.makeEntry( |
| | | "dn: cn=Subentry," + SUFFIX, |
| | | "objectClass: top", |
| | | "objectclass: subentry", |
| | | "subtreeSpecification: {base \"ou=Test SubEntry Manager\"}", |
| | | "cn: Subentry"); |
| | | addOperation = |
| | | connection.processAdd(ldapSubentry.getDN(), |
| | | ldapSubentry.getObjectClasses(), |
| | | ldapSubentry.getUserAttributes(), |
| | | ldapSubentry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(ldapSubentry.getDN())); |
| | | |
| | | // Add test collective subentry. |
| | | collectiveSubentry = TestCaseUtils.makeEntry( |
| | | "dn: cn=Collective Subentry," + SUFFIX, |
| | | "objectClass: top", |
| | | "objectclass: subentry", |
| | | "objectClass: collectiveAttributeSubentry", |
| | | "objectClass: extensibleObject", |
| | | "c-l: Savoie", |
| | | "preferredLanguage;collective: fr", |
| | | "subtreeSpecification: {base \"ou=Test SubEntry Manager\"}", |
| | | "cn: Collective Subentry"); |
| | | addOperation = |
| | | connection.processAdd(collectiveSubentry.getDN(), |
| | | collectiveSubentry.getObjectClasses(), |
| | | collectiveSubentry.getUserAttributes(), |
| | | collectiveSubentry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(collectiveSubentry.getDN())); |
| | | addTestEntries(); |
| | | } |
| | | |
| | | @AfterClass |
| | |
| | | testEntry.getDN().toNormalizedString()), mods); |
| | | assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); |
| | | } |
| | | |
| | | @Test |
| | | public void testSubtreeDelete() throws Exception |
| | | { |
| | | String[] args = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "-J", OID_SUBTREE_DELETE_CONTROL + ":true", |
| | | "--noPropertiesFile", |
| | | SUFFIX |
| | | }; |
| | | assertEquals(LDAPDelete.mainDelete(args, false, null, System.err), 0); |
| | | |
| | | assertTrue(DirectoryServer.getSubentryManager().getCollectiveSubentries( |
| | | DN.decode("uid=rogasawara," + BASE)).isEmpty()); |
| | | |
| | | assertTrue(DirectoryServer.getSubentryManager().getSubentries( |
| | | DN.decode("uid=rogasawara," + BASE)).isEmpty()); |
| | | |
| | | // Re-add entries. |
| | | addTestEntries(); |
| | | } |
| | | |
| | | @Test |
| | | public void testSubtreeModify() throws Exception |
| | | { |
| | | String OLDBASE = "ou=Test SubEntry Manager"; |
| | | String NEWBASE = "ou=New SubEntry Manager Base"; |
| | | |
| | | String newPath = TestCaseUtils.createTempFile( |
| | | "dn: " + BASE, |
| | | "changetype: moddn", |
| | | "newRDN: " + NEWBASE, |
| | | "deleteOldRDN: 1"); |
| | | |
| | | String[] newArgs = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "--noPropertiesFile", |
| | | "-f", newPath |
| | | }; |
| | | assertEquals(LDAPModify.mainModify(newArgs, false, null, System.err), 0); |
| | | |
| | | assertNotNull(DirectoryServer.getEntry(DN.decode( |
| | | "uid=rogasawara," + NEWBASE + "," + SUFFIX))); |
| | | assertTrue(DirectoryServer.getSubentryManager().getCollectiveSubentries( |
| | | DN.decode("uid=rogasawara," + NEWBASE + "," + SUFFIX)).isEmpty()); |
| | | assertTrue(DirectoryServer.getSubentryManager().getSubentries( |
| | | DN.decode("uid=rogasawara," + NEWBASE + "," + SUFFIX)).isEmpty()); |
| | | |
| | | // Move it back. |
| | | String oldPath = TestCaseUtils.createTempFile( |
| | | "dn: " + NEWBASE + "," + SUFFIX, |
| | | "changetype: moddn", |
| | | "newRDN: " + OLDBASE, |
| | | "deleteOldRDN: 1"); |
| | | String[] oldArgs = |
| | | { |
| | | "-h", "127.0.0.1", |
| | | "-p", String.valueOf(TestCaseUtils.getServerLdapPort()), |
| | | "-D", "cn=Directory Manager", |
| | | "-w", "password", |
| | | "--noPropertiesFile", |
| | | "-f", oldPath |
| | | }; |
| | | assertEquals(LDAPModify.mainModify(oldArgs, false, null, System.err), 0); |
| | | |
| | | assertNotNull(DirectoryServer.getEntry(DN.decode( |
| | | "uid=rogasawara," + OLDBASE + "," + SUFFIX))); |
| | | assertFalse(DirectoryServer.getSubentryManager().getCollectiveSubentries( |
| | | DN.decode("uid=rogasawara," + OLDBASE + "," + SUFFIX)).isEmpty()); |
| | | assertFalse(DirectoryServer.getSubentryManager().getSubentries( |
| | | DN.decode("uid=rogasawara," + OLDBASE + "," + SUFFIX)).isEmpty()); |
| | | } |
| | | |
| | | private void addTestEntries() throws Exception |
| | | { |
| | | InternalClientConnection connection = |
| | | InternalClientConnection.getRootConnection(); |
| | | |
| | | // Add suffix entry. |
| | | DN suffixDN = DN.decode(SUFFIX); |
| | | if (DirectoryServer.getEntry(suffixDN) == null) |
| | | { |
| | | Entry suffixEntry = StaticUtils.createEntry(suffixDN); |
| | | AddOperation addOperation = |
| | | connection.processAdd(suffixEntry.getDN(), |
| | | suffixEntry.getObjectClasses(), |
| | | suffixEntry.getUserAttributes(), |
| | | suffixEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(suffixEntry.getDN())); |
| | | } |
| | | |
| | | // Add base entry. |
| | | DN baseDN = DN.decode(BASE); |
| | | if (DirectoryServer.getEntry(baseDN) == null) |
| | | { |
| | | Entry baseEntry = StaticUtils.createEntry(baseDN); |
| | | AddOperation addOperation = |
| | | connection.processAdd(baseEntry.getDN(), |
| | | baseEntry.getObjectClasses(), |
| | | baseEntry.getUserAttributes(), |
| | | baseEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(baseEntry.getDN())); |
| | | } |
| | | |
| | | // Add test entry. |
| | | testEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=rogasawara," + BASE, |
| | | "objectclass: top", |
| | | "objectclass: person", |
| | | "objectclass: organizationalPerson", |
| | | "objectclass: inetOrgPerson", |
| | | "uid: rogasawara", |
| | | "userpassword: password", |
| | | "mail: rogasawara@example.com", |
| | | "givenname: Rodney", |
| | | "sn: Ogasawara", |
| | | "cn: Rodney Ogasawara", |
| | | "title: Sales, Director" |
| | | ); |
| | | AddOperation addOperation = |
| | | connection.processAdd(testEntry.getDN(), |
| | | testEntry.getObjectClasses(), |
| | | testEntry.getUserAttributes(), |
| | | testEntry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(testEntry.getDN())); |
| | | |
| | | // Add test subentry. |
| | | ldapSubentry = TestCaseUtils.makeEntry( |
| | | "dn: cn=Subentry," + SUFFIX, |
| | | "objectClass: top", |
| | | "objectclass: subentry", |
| | | "subtreeSpecification: {base \"ou=Test SubEntry Manager\"}", |
| | | "cn: Subentry"); |
| | | addOperation = |
| | | connection.processAdd(ldapSubentry.getDN(), |
| | | ldapSubentry.getObjectClasses(), |
| | | ldapSubentry.getUserAttributes(), |
| | | ldapSubentry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(ldapSubentry.getDN())); |
| | | |
| | | // Add test collective subentry. |
| | | collectiveSubentry = TestCaseUtils.makeEntry( |
| | | "dn: cn=Collective Subentry," + SUFFIX, |
| | | "objectClass: top", |
| | | "objectclass: subentry", |
| | | "objectClass: collectiveAttributeSubentry", |
| | | "objectClass: extensibleObject", |
| | | "c-l: Savoie", |
| | | "preferredLanguage;collective: fr", |
| | | "subtreeSpecification: {base \"ou=Test SubEntry Manager\"}", |
| | | "cn: Collective Subentry"); |
| | | addOperation = |
| | | connection.processAdd(collectiveSubentry.getDN(), |
| | | collectiveSubentry.getObjectClasses(), |
| | | collectiveSubentry.getUserAttributes(), |
| | | collectiveSubentry.getOperationalAttributes()); |
| | | assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS); |
| | | assertNotNull(DirectoryServer.getEntry(collectiveSubentry.getDN())); |
| | | } |
| | | } |
| | |
| | | |
| | | |
| | | /** |
| | | * Test that a delete subtree changes the correct entries under |
| | | * the correct suffixes. |
| | | * |
| | | * FIXME: re-enable when CR 6959320 is fixed. |
| | | * Test that a delete subtree changes the correct entries |
| | | * under the correct suffixes. |
| | | * |
| | | * @throws Exception If an unexpected result is returned. |
| | | * |
| | | */ |
| | | @Test(enabled=false) |
| | | @Test() |
| | | public void testReferentialDeleteTree() throws Exception { |
| | | // Add attributes interested in: member, uniquemember, seealso. |
| | | replaceAttrEntry(configDN, dsConfigAttrType,"member"); |
| | |
| | | // Perform the subtree delete. |
| | | deleteSubtree(oldSuperior); |
| | | |
| | | // Check group membership before delete. |
| | | // |
| | | // This simply checks that the group cache is updated |
| | | // rather than RI plugin works (it fails at the moment). |
| | | // |
| | | // isMember(tgroup, false, user1, user2, user3); |
| | | // Check that the group cache is updated. |
| | | isMember(tgroup, false, user1, user2, user3); |
| | | |
| | | // Check values exist as before delete. |
| | | isAttributeValueEntry(tgroup, false, "member", user1, user2, user3); |