From 06ce5a9bf602432fdc7b1da52781b8c0c5ea88e0 Mon Sep 17 00:00:00 2001 From: Ulrik Sandberg Date: Sun, 3 Oct 2010 22:18:34 +0000 Subject: [PATCH] Added attributeExists method so user can distinguish between attribute not exists or exists with no value. Improved javadoc for getObjectAttribute and getStringAttribute to reflect the new meaning of null. LDAP-215 --- changelog.txt | 6 +- .../ldap/core/DirContextAdapter.java | 2740 +++++++++-------- .../ldap/core/DirContextOperations.java | 506 +-- .../ldap/core/DirContextAdapterTest.java | 2298 +++++++------- 4 files changed, 2799 insertions(+), 2751 deletions(-) diff --git a/changelog.txt b/changelog.txt index 65d2164f..a714f2d9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -11,7 +11,7 @@ http://www.ietf.org/rfc/rfc2255.txt http://www.ietf.org/rfc/rfc2256.txt http://www.ietf.org/rfc/rfc2696.txt -Changes in version 1.3.1 (Summer 2010) +Changes in version 1.3.1 (October 2010) ------------------------------------------- * Added an object-directory mapping framework (ODM). Contributed by Paul Harvey. @@ -22,6 +22,10 @@ Changes in version 1.3.1 (Summer 2010) associated mapper with an indication that the response is different for each search result. (LDAP-185) +* DirContextAdapter.getObjectAttribute now returns null if the attribute + exists but with no value. Added method attributeExists for cases where + it has to be detected whether it was one or the other. (LDAP-215) + * Added utility methods for converting a Windows security identifier (SID) between a binary format and a slightly more readable string format. http://msdn.microsoft.com/en-us/library/aa379571%28VS.85%29.aspx diff --git a/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java b/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java index 62bc04d7..f0fbb321 100644 --- a/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java +++ b/core/src/main/java/org/springframework/ldap/core/DirContextAdapter.java @@ -1,1364 +1,1376 @@ -/* - * Copyright 2005-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ldap.core; - -import java.util.ArrayList; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.List; -import java.util.SortedSet; -import java.util.TreeSet; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.NameNotFoundException; -import javax.naming.NameParser; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.BasicAttribute; -import javax.naming.directory.BasicAttributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; - -import org.apache.commons.lang.ArrayUtils; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.ldap.NoSuchAttributeException; -import org.springframework.ldap.support.LdapUtils; -import org.springframework.util.StringUtils; - -/** - * Adapter that implements the interesting methods of the DirContext interface. - * In particular it contains utility methods for getting and setting attributes. - * Using the - * {@link org.springframework.ldap.core.support.DefaultDirObjectFactory} in your - * ContextSource (which is the default) you will receive instances - * of this class from searches and lookups. This can be particularly useful when - * updating data, since this class implements - * {@link AttributeModificationsAware}, providing a - * {@link #getModificationItems()} method. When in update mode, an object of - * this class keeps track of the changes made to its attributes, making them - * available as an array of ModificationItem objects, suitable as - * input to {@link LdapTemplate#modifyAttributes(DirContextOperations)}. - * - * @see #setAttributeValue(String, Object) - * @see #setAttributeValues(String, Object[]) - * @see #getStringAttribute(String) - * @see #getStringAttributes(String) - * @see #getObjectAttribute(String) - * @see #addAttributeValue(String, Object) - * @see #removeAttributeValue(String, Object) - * @see #setUpdateMode(boolean) - * @see #isUpdateMode() - * - * @author Magnus Robertsson - * @author Andreas Ronge - * @author Adam Skogman - * @author Mattias Hellborg Arthursson - */ -public class DirContextAdapter implements DirContextOperations { - - private static final boolean DONT_ADD_IF_DUPLICATE_EXISTS = false; - - private static final String EMPTY_STRING = ""; - - private static final boolean ORDER_DOESNT_MATTER = false; - - private static Log log = LogFactory.getLog(DirContextAdapter.class); - - private final Attributes originalAttrs; - - private DistinguishedName dn; - - private DistinguishedName base; - - private boolean updateMode = false; - - private Attributes updatedAttrs; - - private String referralUrl; - - /** - * Default constructor. - */ - public DirContextAdapter() { - this(null, null, null); - } - - /** - * Create a new DirContextAdapter from the supplied DN String. - * @param dnString the DN string. Must be syntactically correct, or an - * exception will be thrown. - */ - public DirContextAdapter(String dnString) { - this(new DistinguishedName(dnString)); - } - - /** - * Create a new adapter from the supplied dn. - * - * @param dn the dn. - */ - public DirContextAdapter(Name dn) { - this(null, dn); - } - - /** - * Create a new adapter from the supplied attributes and dn. - * - * @param attrs the attributes. - * @param dn the dn. - */ - public DirContextAdapter(Attributes attrs, Name dn) { - this(attrs, dn, null); - } - - /** - * Create a new adapter from the supplied attributes, dn, and base. - * - * @param attrs the attributes. - * @param dn the dn. - * @param base the base name. - */ - public DirContextAdapter(Attributes attrs, Name dn, Name base) { - this(attrs, dn, base, null); - } - - /** - * Create a new adapter from the supplied attributes, dn, base, and referral - * url. - * @param attrs the attributes. - * @param dn the dn. - * @param base the base. - * @param referralUrl the referral url (if this instance results from a - * referral). - */ - public DirContextAdapter(Attributes attrs, Name dn, Name base, - String referralUrl) { - if (attrs != null) { - this.originalAttrs = attrs; - } - else { - this.originalAttrs = new BasicAttributes(true); - } - if (dn != null) { - this.dn = new DistinguishedName(dn); - } - else { - this.dn = new DistinguishedName(); - } - if (base != null) { - this.base = new DistinguishedName(base); - } - else { - this.base = new DistinguishedName(); - } - if (referralUrl != null) { - this.referralUrl = referralUrl; - } - else { - this.referralUrl = EMPTY_STRING; - } - } - - /** - * Constructor for cloning an existing adapter. - * - * @param master The adapter to be copied. - */ - protected DirContextAdapter(DirContextAdapter master) { - this.originalAttrs = (Attributes) master.originalAttrs.clone(); - this.dn = master.dn; - this.updatedAttrs = (Attributes) master.updatedAttrs.clone(); - this.updateMode = master.updateMode; - } - - /** - * Sets the update mode. The update mode should be false for a - * new entry and true for an existing entry that is being - * updated. - * - * @param mode Update mode. - */ - public void setUpdateMode(boolean mode) { - this.updateMode = mode; - if (updateMode) { - updatedAttrs = new BasicAttributes(true); - } - } - - /* - * @see org.springframework.ldap.support.DirContextOperations#isUpdateMode() - */ - public boolean isUpdateMode() { - return updateMode; - } - - /* - * @seeorg.springframework.ldap.support.DirContextOperations# - * getNamesOfModifiedAttributes() - */ - public String[] getNamesOfModifiedAttributes() { - - List tmpList = new ArrayList(); - - NamingEnumeration attributesEnumeration; - if (isUpdateMode()) { - attributesEnumeration = updatedAttrs.getAll(); - } - else { - attributesEnumeration = originalAttrs.getAll(); - } - - try { - while (attributesEnumeration.hasMore()) { - Attribute oneAttribute = (Attribute) attributesEnumeration - .next(); - tmpList.add(oneAttribute.getID()); - } - } - catch (NamingException e) { - throw LdapUtils.convertLdapException(e); - } - finally { - closeNamingEnumeration(attributesEnumeration); - } - - return (String[]) tmpList.toArray(new String[0]); - } - - private void closeNamingEnumeration(NamingEnumeration enumeration) { - try { - if (enumeration != null) { - enumeration.close(); - } - } - catch (NamingException e) { - // Never mind this - } - } - - /* - * @seeorg.springframework.ldap.support.AttributeModificationsAware# - * getModificationItems() - */ - public ModificationItem[] getModificationItems() { - if (!updateMode) { - return new ModificationItem[0]; - } - - List tmpList = new LinkedList(); - NamingEnumeration attributesEnumeration = null; - try { - attributesEnumeration = updatedAttrs.getAll(); - - // find attributes that have been changed, removed or added - while (attributesEnumeration.hasMore()) { - Attribute oneAttr = (Attribute) attributesEnumeration.next(); - - collectModifications(oneAttr, tmpList); - } - } - catch (NamingException e) { - throw LdapUtils.convertLdapException(e); - } - finally { - closeNamingEnumeration(attributesEnumeration); - } - - if (log.isDebugEnabled()) { - log.debug("Number of modifications:" + tmpList.size()); - } - - return (ModificationItem[]) tmpList - .toArray(new ModificationItem[tmpList.size()]); - } - - /** - * Collect all modifications for the changed attribute. If no changes have - * been made, return immediately. If modifications have been made, and the - * original size as well as the updated size of the attribute is 1, replace - * the attribute. If the size of the updated attribute is 0, remove the - * attribute. Otherwise, the attribute is a multi-value attribute; if it's - * an ordered one it should be replaced in its entirety to preserve the new - * ordering, if not all modifications to the original value (removals and - * additions) will be collected individually. - * - * @param changedAttr the value of the changed attribute. - * @param modificationList the list in which to add the modifications. - * @throws NamingException if thrown by called Attribute methods. - */ - private void collectModifications(Attribute changedAttr, - List modificationList) throws NamingException { - Attribute currentAttribute = originalAttrs.get(changedAttr.getID()); - - if (changedAttr.equals(currentAttribute)) { - // No changes - return; - } - else if (currentAttribute != null && currentAttribute.size() == 1 - && changedAttr.size() == 1) { - // Replace single-vale attribute. - modificationList.add(new ModificationItem( - DirContext.REPLACE_ATTRIBUTE, changedAttr)); - } - else if (changedAttr.size() == 0 && currentAttribute != null) { - // Attribute has been removed. - modificationList.add(new ModificationItem( - DirContext.REMOVE_ATTRIBUTE, changedAttr)); - } - else if ((currentAttribute == null || currentAttribute.size() == 0) - && changedAttr.size() > 0) { - // Attribute has been added. - modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, - changedAttr)); - } - else if (changedAttr.size() > 0 && changedAttr.isOrdered()) { - // This is a multivalue attribute and it is ordered - the original - // value should be replaced with the new values so that the ordering - // is preserved. - modificationList.add(new ModificationItem( - DirContext.REPLACE_ATTRIBUTE, changedAttr)); - } - else if (changedAttr.size() > 0) { - // Change of multivalue Attribute. Collect additions and removals - // individually. - List myModifications = new LinkedList(); - collectModifications(currentAttribute, changedAttr, myModifications); - - if (myModifications.isEmpty()) { - // This means that the attributes are not equal, but the - // actual values are the same - thus the order must have - // changed. This should result in a REPLACE_ATTRIBUTE operation. - myModifications.add(new ModificationItem( - DirContext.REPLACE_ATTRIBUTE, changedAttr)); - } - - modificationList.addAll(myModifications); - } - } - - private void collectModifications(Attribute originalAttr, - Attribute changedAttr, List modificationList) - throws NamingException { - - Attribute originalClone = (Attribute) originalAttr.clone(); - Attribute addedValuesAttribute = new BasicAttribute(originalAttr - .getID()); - - for (int i = 0; i < changedAttr.size(); i++) { - Object attributeValue = changedAttr.get(i); - if (!originalClone.remove(attributeValue)) { - addedValuesAttribute.add(attributeValue); - } - } - - // We have now traversed and removed all values from the original that - // were also present in the new values. The remaining values in the - // original must be the ones that were removed. - if (originalClone.size() > 0) { - modificationList.add(new ModificationItem( - DirContext.REMOVE_ATTRIBUTE, originalClone)); - } - - if (addedValuesAttribute.size() > 0) { - modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, - addedValuesAttribute)); - } - } - - /** - * returns true if the attribute is empty. It is empty if a == null, size == - * 0 or get() == null or an exception if thrown when accessing the get - * method - */ - private boolean isEmptyAttribute(Attribute a) { - try { - return (a == null || a.size() == 0 || a.get() == null); - } - catch (NamingException e) { - return true; - } - } - - /** - * Compare the existing attribute name with the values on the - * array values. The order of the array must be the same order - * as the existing multivalued attribute. - *

- * Also handles the case where the values have been reset to the original - * values after a previous change. For example, changing - * [a,b,c] to [a,b] and then back to - * [a,b,c] again must result in this method returning - * true so the first change can be overwritten with the latest - * change. - * - * @param name Name of the original multi-valued attribute. - * @param values Array of values to check if they have been changed. - * @return true if there has been a change compared to original attribute, - * or a previous update - */ - private boolean isChanged(String name, Object[] values, boolean orderMatters) { - - Attribute orig = originalAttrs.get(name); - Attribute prev = updatedAttrs.get(name); - - // values == null and values.length == 0 is treated the same way - boolean emptyNewValue = (values == null || values.length == 0); - - // Setting to empty --------------------- - if (emptyNewValue) { - // FALSE: if both are null, it is not changed (both don't exist) - // TRUE: if new value is null and old value exists (should be - // removed) - // TODO Also include prev in null check - // TODO Also check if there is a single null element - if (orig != null) { - return true; - } - return false; - } - - // NOT setting to empty ------------------- - - // TRUE if existing value is null - if (orig == null) { - return true; - } - - // TRUE if different length compared to original attributes - if (orig.size() != values.length) { - return true; - } - - // TRUE if different length compared to previously updated attributes - if (prev != null && prev.size() != values.length) { - return true; - } - - // Check contents of arrays - - // Order DOES matter, e.g. first names - try { - for (int i = 0; i < orig.size(); i++) { - Object obj = orig.get(i); - // TRUE if one value is not equal - if (!(obj instanceof String)) { - return true; - } - if (orderMatters) { - // check only the string with same index - if (!values[i].equals(obj)) { - return true; - } - } - else { - // check all strings - if (!ArrayUtils.contains(values, obj)) { - return true; - } - } - } - - } - catch (NamingException e) { - // TRUE if we can't access the value - return true; - } - - if (prev != null) { - // Also check against updatedAttrs, since there might have been - // a previous update - try { - for (int i = 0; i < prev.size(); i++) { - Object obj = prev.get(i); - // TRUE if one value is not equal - if (!(obj instanceof String)) { - return true; - } - if (orderMatters) { - // check only the string with same index - if (!values[i].equals(obj)) { - return true; - } - } - else { - // check all strings - if (!ArrayUtils.contains(values, obj)) { - return true; - } - } - } - - } - catch (NamingException e) { - // TRUE if we can't access the value - return true; - } - } - // FALSE since we have compared all values - return false; - } - - /** - * Checks if an entry has a specific attribute. - * - * This method simply calls exists(String) with the attribute name. - * - * @param attr the attribute to check. - * @return true if attribute exists in entry. - */ - protected final boolean exists(Attribute attr) { - return exists(attr.getID()); - } - - /** - * Checks if the attribute exists in this entry, either it was read or it - * has been added and update() has been called. - * - * @param attrId id of the attribute to check. - * @return true if the attribute exists in the entry. - */ - protected final boolean exists(String attrId) { - return originalAttrs.get(attrId) != null; - } - - /* - * @see - * org.springframework.ldap.support.DirContextOperations#getStringAttribute - * (java.lang.String) - */ - public String getStringAttribute(String name) { - return (String) getObjectAttribute(name); - } - - /* - * @see - * org.springframework.ldap.support.DirContextOperations#getObjectAttribute - * (java.lang.String) - */ - public Object getObjectAttribute(String name) { - Attribute oneAttr = originalAttrs.get(name); - if (oneAttr == null || oneAttr.size() == 0) { // LDAP-215 - return null; - } - try { - return oneAttr.get(); - } - catch (NamingException e) { - throw LdapUtils.convertLdapException(e); - } - } - - /* - * @see - * org.springframework.ldap.support.DirContextOperations#setAttributeValue - * (java.lang.String, java.lang.Object) - */ - public void setAttributeValue(String name, Object value) { - // new entry - if (!updateMode && value != null) { - originalAttrs.put(name, value); - } - - // updating entry - if (updateMode) { - BasicAttribute attribute = new BasicAttribute(name); - if (value != null) { - attribute.add(value); - } - updatedAttrs.put(attribute); - } - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.ldap.core.DirContextOperations#addAttributeValue( - * java.lang.String, java.lang.Object) - */ - public void addAttributeValue(String name, Object value) { - addAttributeValue(name, value, DONT_ADD_IF_DUPLICATE_EXISTS); - } - - public void addAttributeValue(String name, Object value, - boolean addIfDuplicateExists) { - if (!updateMode && value != null) { - Attribute attr = originalAttrs.get(name); - if (attr == null) { - originalAttrs.put(name, value); - } - else { - attr.add(value); - } - } - else if (updateMode) { - Attribute attr = updatedAttrs.get(name); - if (attr == null) { - if (originalAttrs.get(name) == null) { - // No match in the original attributes - - // add a new Attribute to updatedAttrs - updatedAttrs.put(name, value); - } - else { - // The attribute exists in the original attributes - clone - // that and add the new entry to it - attr = (Attribute) originalAttrs.get(name).clone(); - if (addIfDuplicateExists || !attr.contains(value)) { - attr.add(value); - } - updatedAttrs.put(attr); - } - } - else { - attr.add(value); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.ldap.core.DirContextOperations#removeAttributeValue - * (java.lang.String, java.lang.Object) - */ - public void removeAttributeValue(String name, Object value) { - if (!updateMode && value != null) { - Attribute attr = originalAttrs.get(name); - if (attr != null) { - attr.remove(value); - if (attr.size() == 0) { - originalAttrs.remove(name); - } - } - } - else if (updateMode) { - Attribute attr = updatedAttrs.get(name); - if (attr == null) { - if (originalAttrs.get(name) != null) { - attr = (Attribute) originalAttrs.get(name).clone(); - attr.remove(value); - updatedAttrs.put(attr); - } - } - else { - attr.remove(value); - } - } - } - - /* - * @see - * org.springframework.ldap.support.DirContextOperations#setAttributeValues - * (java.lang.String, java.lang.Object[]) - */ - public void setAttributeValues(String name, Object[] values) { - setAttributeValues(name, values, ORDER_DOESNT_MATTER); - } - - /* - * @see - * org.springframework.ldap.support.DirContextOperations#setAttributeValues - * (java.lang.String, java.lang.Object[], boolean) - */ - public void setAttributeValues(String name, Object[] values, - boolean orderMatters) { - Attribute a = new BasicAttribute(name, orderMatters); - - for (int i = 0; values != null && i < values.length; i++) { - a.add(values[i]); - } - - // only change the original attribute if not in update mode - if (!updateMode && values != null && values.length > 0) { - // don't save empty arrays - originalAttrs.put(a); - } - - // possible to set an already existing attribute to an empty array - if (updateMode && isChanged(name, values, orderMatters)) { - updatedAttrs.put(a); - } - } - - /* - * @see org.springframework.ldap.support.DirContextOperations#update() - */ - public void update() { - NamingEnumeration attributesEnumeration = null; - - try { - attributesEnumeration = updatedAttrs.getAll(); - - // find what to update - while (attributesEnumeration.hasMore()) { - Attribute a = (Attribute) attributesEnumeration.next(); - - // if it does not exist it should be added - if (isEmptyAttribute(a)) { - originalAttrs.remove(a.getID()); - } - else { - // Otherwise it should be set. - originalAttrs.put(a); - } - } - } - catch (NamingException e) { - throw LdapUtils.convertLdapException(e); - } - finally { - closeNamingEnumeration(attributesEnumeration); - } - - // Reset the attributes to be updated - updatedAttrs = new BasicAttributes(true); - } - - /* - * @see - * org.springframework.ldap.core.DirContextOperations#getStringAttributes - * (java.lang.String) - */ - public String[] getStringAttributes(String name) { - try { - return (String[]) collectAttributeValuesAsList(name).toArray( - new String[0]); - } - catch (NoSuchAttributeException e) { - // The attribute does not exist - contract says to return null. - return null; - } - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.ldap.core.DirContextOperations#getObjectAttributes - * (java.lang.String) - */ - public Object[] getObjectAttributes(String name) { - try { - return collectAttributeValuesAsList(name).toArray(new Object[0]); - } - catch (NoSuchAttributeException e) { - // The attribute does not exist - contract says to return null. - return null; - } - } - - private List collectAttributeValuesAsList(String name) { - List list = new LinkedList(); - LdapUtils.collectAttributeValues(originalAttrs, name, list); - return list; - } - - /* - * @seeorg.springframework.ldap.support.DirContextOperations# - * getAttributeSortedStringSet(java.lang.String) - */ - public SortedSet getAttributeSortedStringSet(String name) { - try { - TreeSet attrSet = new TreeSet(); - LdapUtils.collectAttributeValues(originalAttrs, name, attrSet); - return attrSet; - } - catch (NoSuchAttributeException e) { - // The attribute does not exist - contract says to return null. - return null; - } - } - - /** - * Set the supplied attribute. - * - * @param attribute the attribute to set. - */ - public void setAttribute(Attribute attribute) { - if (!updateMode) { - originalAttrs.put(attribute); - } - else { - updatedAttrs.put(attribute); - } - } - - /** - * Get all attributes. - * - * @return all attributes. - */ - public Attributes getAttributes() { - return originalAttrs; - } - - /** - * @see javax.naming.directory.DirContext#getAttributes(Name) - */ - public Attributes getAttributes(Name name) throws NamingException { - return getAttributes(name.toString()); - } - - /** - * @see javax.naming.directory.DirContext#getAttributes(String) - */ - public Attributes getAttributes(String name) throws NamingException { - if (StringUtils.hasLength(name)) { - throw new NameNotFoundException(); - } - return (Attributes) originalAttrs.clone(); - } - - /** - * @see javax.naming.directory.DirContext#getAttributes(Name, String[]) - */ - public Attributes getAttributes(Name name, String[] attrIds) - throws NamingException { - return getAttributes(name.toString(), attrIds); - } - - /** - * @see javax.naming.directory.DirContext#getAttributes(String, String[]) - */ - public Attributes getAttributes(String name, String[] attrIds) - throws NamingException { - if (StringUtils.hasLength(name)) { - throw new NameNotFoundException(); - } - - Attributes a = new BasicAttributes(true); - Attribute target; - for (int i = 0; i < attrIds.length; i++) { - target = originalAttrs.get(attrIds[i]); - if (target != null) { - a.put(target); - } - } - - return a; - } - - /** - * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name, - * int, javax.naming.directory.Attributes) - */ - public void modifyAttributes(Name name, int modOp, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#modifyAttributes(String, int, - * Attributes) - */ - public void modifyAttributes(String name, int modOp, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#modifyAttributes(Name, - * ModificationItem[]) - */ - public void modifyAttributes(Name name, ModificationItem[] mods) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#modifyAttributes(String, - * ModificationItem[]) - */ - public void modifyAttributes(String name, ModificationItem[] mods) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#bind(Name, Object, Attributes) - */ - public void bind(Name name, Object obj, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#bind(String, Object, Attributes) - */ - public void bind(String name, Object obj, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#rebind(Name, Object, Attributes) - */ - public void rebind(Name name, Object obj, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#rebind(String, Object, Attributes) - */ - public void rebind(String name, Object obj, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#createSubcontext(Name, Attributes) - */ - public DirContext createSubcontext(Name name, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#createSubcontext(String, - * Attributes) - */ - public DirContext createSubcontext(String name, Attributes attrs) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#getSchema(Name) - */ - public DirContext getSchema(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#getSchema(String) - */ - public DirContext getSchema(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#getSchemaClassDefinition(Name) - */ - public DirContext getSchemaClassDefinition(Name name) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#getSchemaClassDefinition(String) - */ - public DirContext getSchemaClassDefinition(String name) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(Name, Attributes, String[]) - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes, - String[] attributesToReturn) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(String, Attributes, - * String[]) - */ - public NamingEnumeration search(String name, Attributes matchingAttributes, - String[] attributesToReturn) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(Name, Attributes) - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(String, Attributes) - */ - public NamingEnumeration search(String name, Attributes matchingAttributes) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(Name, String, - * SearchControls) - */ - public NamingEnumeration search(Name name, String filter, - SearchControls cons) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(String, String, - * SearchControls) - */ - public NamingEnumeration search(String name, String filter, - SearchControls cons) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(Name, String, Object[], - * SearchControls) - */ - public NamingEnumeration search(Name name, String filterExpr, - Object[] filterArgs, SearchControls cons) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.directory.DirContext#search(String, String, Object[], - * SearchControls) - */ - public NamingEnumeration search(String name, String filterExpr, - Object[] filterArgs, SearchControls cons) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#lookup(Name) - */ - public Object lookup(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#lookup(String) - */ - public Object lookup(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#bind(Name, Object) - */ - public void bind(Name name, Object obj) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#bind(String, Object) - */ - public void bind(String name, Object obj) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#rebind(Name, Object) - */ - public void rebind(Name name, Object obj) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#rebind(String, Object) - */ - public void rebind(String name, Object obj) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#unbind(Name) - */ - public void unbind(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#unbind(String) - */ - public void unbind(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#rename(Name, Name) - */ - public void rename(Name oldName, Name newName) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#rename(String, String) - */ - public void rename(String oldName, String newName) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#list(Name) - */ - public NamingEnumeration list(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#list(String) - */ - public NamingEnumeration list(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#listBindings(Name) - */ - public NamingEnumeration listBindings(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#listBindings(String) - */ - public NamingEnumeration listBindings(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#destroySubcontext(Name) - */ - public void destroySubcontext(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#destroySubcontext(String) - */ - public void destroySubcontext(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#createSubcontext(Name) - */ - public Context createSubcontext(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#createSubcontext(String) - */ - public Context createSubcontext(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#lookupLink(Name) - */ - public Object lookupLink(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#lookupLink(String) - */ - public Object lookupLink(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#getNameParser(Name) - */ - public NameParser getNameParser(Name name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#getNameParser(String) - */ - public NameParser getNameParser(String name) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#composeName(Name, Name) - */ - public Name composeName(Name name, Name prefix) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#composeName(String, String) - */ - public String composeName(String name, String prefix) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#addToEnvironment(String, Object) - */ - public Object addToEnvironment(String propName, Object propVal) - throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#removeFromEnvironment(String) - */ - public Object removeFromEnvironment(String propName) throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#getEnvironment() - */ - public Hashtable getEnvironment() throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#close() - */ - public void close() throws NamingException { - throw new UnsupportedOperationException("Not implemented."); - } - - /** - * @see javax.naming.Context#getNameInNamespace() - */ - public String getNameInNamespace() { - DistinguishedName result = new DistinguishedName(dn); - result.prepend(base); - return result.toString(); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.ldap.support.DirContextOperations#getDn() - */ - public Name getDn() { - return new DistinguishedName(dn); - } - - /* - * (non-Javadoc) - * - * @see - * org.springframework.ldap.support.DirContextOperations#setDn(javax.naming - * .Name) - */ - public final void setDn(Name dn) { - if (!updateMode) { - this.dn = new DistinguishedName(dn.toString()); - } - else { - throw new IllegalStateException( - "Not possible to call setDn() on a DirContextAdapter in update mode"); - } - - } - - /** - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object obj) { - // A subclass with identical values should NOT be considered equal. - // EqualsBuilder in commons-lang cannot handle subclasses correctly. - if (obj == null || obj.getClass() != this.getClass()) { - return false; - } - return EqualsBuilder.reflectionEquals(this, obj); - } - - /** - * @see Object#hashCode() - */ - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - - /** - * @see java.lang.Object#toString() - */ - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append(getClass().getName()); - buf.append(":"); - if (dn != null) { - buf.append(" dn=" + dn); - } - buf.append(" {"); - - try { - for (NamingEnumeration i = originalAttrs.getAll(); i.hasMore();) { - Attribute attribute = (Attribute) i.next(); - if (attribute.size() == 1) { - buf.append(attribute.getID()); - buf.append('='); - buf.append(attribute.get()); - } - else { - for (int j = 0; j < attribute.size(); j++) { - if (j > 0) { - buf.append(", "); - } - buf.append(attribute.getID()); - buf.append('['); - buf.append(j); - buf.append("]="); - buf.append(attribute.get(j)); - } - } - - if (i.hasMore()) { - buf.append(", "); - } - } - } - catch (NamingException e) { - log.warn("Error in toString()"); - } - buf.append('}'); - - return buf.toString(); - } - - /* - * (non-Javadoc) - * - * @see org.springframework.ldap.core.DirContextOperations#getReferralUrl() - */ - public String getReferralUrl() { - return referralUrl; - } - - /* - * (non-Javadoc) - * - * @see org.springframework.ldap.core.DirContextOperations#isReferral() - */ - public boolean isReferral() { - return StringUtils.hasLength(referralUrl); - } - -} +/* + * Copyright 2005-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ldap.core; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.ldap.NoSuchAttributeException; +import org.springframework.ldap.support.LdapUtils; +import org.springframework.util.StringUtils; + +/** + * Adapter that implements the interesting methods of the DirContext interface. + * In particular it contains utility methods for getting and setting attributes. + * Using the + * {@link org.springframework.ldap.core.support.DefaultDirObjectFactory} in your + * ContextSource (which is the default) you will receive instances + * of this class from searches and lookups. This can be particularly useful when + * updating data, since this class implements + * {@link AttributeModificationsAware}, providing a + * {@link #getModificationItems()} method. When in update mode, an object of + * this class keeps track of the changes made to its attributes, making them + * available as an array of ModificationItem objects, suitable as + * input to {@link LdapTemplate#modifyAttributes(DirContextOperations)}. + * + * @see #setAttributeValue(String, Object) + * @see #setAttributeValues(String, Object[]) + * @see #getStringAttribute(String) + * @see #getStringAttributes(String) + * @see #getObjectAttribute(String) + * @see #addAttributeValue(String, Object) + * @see #removeAttributeValue(String, Object) + * @see #setUpdateMode(boolean) + * @see #isUpdateMode() + * + * @author Magnus Robertsson + * @author Andreas Ronge + * @author Adam Skogman + * @author Mattias Hellborg Arthursson + */ +public class DirContextAdapter implements DirContextOperations { + + private static final boolean DONT_ADD_IF_DUPLICATE_EXISTS = false; + + private static final String EMPTY_STRING = ""; + + private static final boolean ORDER_DOESNT_MATTER = false; + + private static Log log = LogFactory.getLog(DirContextAdapter.class); + + private final Attributes originalAttrs; + + private DistinguishedName dn; + + private DistinguishedName base; + + private boolean updateMode = false; + + private Attributes updatedAttrs; + + private String referralUrl; + + /** + * Default constructor. + */ + public DirContextAdapter() { + this(null, null, null); + } + + /** + * Create a new DirContextAdapter from the supplied DN String. + * @param dnString the DN string. Must be syntactically correct, or an + * exception will be thrown. + */ + public DirContextAdapter(String dnString) { + this(new DistinguishedName(dnString)); + } + + /** + * Create a new adapter from the supplied dn. + * + * @param dn the dn. + */ + public DirContextAdapter(Name dn) { + this(null, dn); + } + + /** + * Create a new adapter from the supplied attributes and dn. + * + * @param attrs the attributes. + * @param dn the dn. + */ + public DirContextAdapter(Attributes attrs, Name dn) { + this(attrs, dn, null); + } + + /** + * Create a new adapter from the supplied attributes, dn, and base. + * + * @param attrs the attributes. + * @param dn the dn. + * @param base the base name. + */ + public DirContextAdapter(Attributes attrs, Name dn, Name base) { + this(attrs, dn, base, null); + } + + /** + * Create a new adapter from the supplied attributes, dn, base, and referral + * url. + * @param attrs the attributes. + * @param dn the dn. + * @param base the base. + * @param referralUrl the referral url (if this instance results from a + * referral). + */ + public DirContextAdapter(Attributes attrs, Name dn, Name base, + String referralUrl) { + if (attrs != null) { + this.originalAttrs = attrs; + } + else { + this.originalAttrs = new BasicAttributes(true); + } + if (dn != null) { + this.dn = new DistinguishedName(dn); + } + else { + this.dn = new DistinguishedName(); + } + if (base != null) { + this.base = new DistinguishedName(base); + } + else { + this.base = new DistinguishedName(); + } + if (referralUrl != null) { + this.referralUrl = referralUrl; + } + else { + this.referralUrl = EMPTY_STRING; + } + } + + /** + * Constructor for cloning an existing adapter. + * + * @param master The adapter to be copied. + */ + protected DirContextAdapter(DirContextAdapter master) { + this.originalAttrs = (Attributes) master.originalAttrs.clone(); + this.dn = master.dn; + this.updatedAttrs = (Attributes) master.updatedAttrs.clone(); + this.updateMode = master.updateMode; + } + + /** + * Sets the update mode. The update mode should be false for a + * new entry and true for an existing entry that is being + * updated. + * + * @param mode Update mode. + */ + public void setUpdateMode(boolean mode) { + this.updateMode = mode; + if (updateMode) { + updatedAttrs = new BasicAttributes(true); + } + } + + /* + * @see org.springframework.ldap.support.DirContextOperations#isUpdateMode() + */ + public boolean isUpdateMode() { + return updateMode; + } + + /* + * @seeorg.springframework.ldap.support.DirContextOperations# + * getNamesOfModifiedAttributes() + */ + public String[] getNamesOfModifiedAttributes() { + + List tmpList = new ArrayList(); + + NamingEnumeration attributesEnumeration; + if (isUpdateMode()) { + attributesEnumeration = updatedAttrs.getAll(); + } + else { + attributesEnumeration = originalAttrs.getAll(); + } + + try { + while (attributesEnumeration.hasMore()) { + Attribute oneAttribute = (Attribute) attributesEnumeration + .next(); + tmpList.add(oneAttribute.getID()); + } + } + catch (NamingException e) { + throw LdapUtils.convertLdapException(e); + } + finally { + closeNamingEnumeration(attributesEnumeration); + } + + return (String[]) tmpList.toArray(new String[0]); + } + + private void closeNamingEnumeration(NamingEnumeration enumeration) { + try { + if (enumeration != null) { + enumeration.close(); + } + } + catch (NamingException e) { + // Never mind this + } + } + + /* + * @seeorg.springframework.ldap.support.AttributeModificationsAware# + * getModificationItems() + */ + public ModificationItem[] getModificationItems() { + if (!updateMode) { + return new ModificationItem[0]; + } + + List tmpList = new LinkedList(); + NamingEnumeration attributesEnumeration = null; + try { + attributesEnumeration = updatedAttrs.getAll(); + + // find attributes that have been changed, removed or added + while (attributesEnumeration.hasMore()) { + Attribute oneAttr = (Attribute) attributesEnumeration.next(); + + collectModifications(oneAttr, tmpList); + } + } + catch (NamingException e) { + throw LdapUtils.convertLdapException(e); + } + finally { + closeNamingEnumeration(attributesEnumeration); + } + + if (log.isDebugEnabled()) { + log.debug("Number of modifications:" + tmpList.size()); + } + + return (ModificationItem[]) tmpList + .toArray(new ModificationItem[tmpList.size()]); + } + + /** + * Collect all modifications for the changed attribute. If no changes have + * been made, return immediately. If modifications have been made, and the + * original size as well as the updated size of the attribute is 1, replace + * the attribute. If the size of the updated attribute is 0, remove the + * attribute. Otherwise, the attribute is a multi-value attribute; if it's + * an ordered one it should be replaced in its entirety to preserve the new + * ordering, if not all modifications to the original value (removals and + * additions) will be collected individually. + * + * @param changedAttr the value of the changed attribute. + * @param modificationList the list in which to add the modifications. + * @throws NamingException if thrown by called Attribute methods. + */ + private void collectModifications(Attribute changedAttr, + List modificationList) throws NamingException { + Attribute currentAttribute = originalAttrs.get(changedAttr.getID()); + + if (changedAttr.equals(currentAttribute)) { + // No changes + return; + } + else if (currentAttribute != null && currentAttribute.size() == 1 + && changedAttr.size() == 1) { + // Replace single-vale attribute. + modificationList.add(new ModificationItem( + DirContext.REPLACE_ATTRIBUTE, changedAttr)); + } + else if (changedAttr.size() == 0 && currentAttribute != null) { + // Attribute has been removed. + modificationList.add(new ModificationItem( + DirContext.REMOVE_ATTRIBUTE, changedAttr)); + } + else if ((currentAttribute == null || currentAttribute.size() == 0) + && changedAttr.size() > 0) { + // Attribute has been added. + modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, + changedAttr)); + } + else if (changedAttr.size() > 0 && changedAttr.isOrdered()) { + // This is a multivalue attribute and it is ordered - the original + // value should be replaced with the new values so that the ordering + // is preserved. + modificationList.add(new ModificationItem( + DirContext.REPLACE_ATTRIBUTE, changedAttr)); + } + else if (changedAttr.size() > 0) { + // Change of multivalue Attribute. Collect additions and removals + // individually. + List myModifications = new LinkedList(); + collectModifications(currentAttribute, changedAttr, myModifications); + + if (myModifications.isEmpty()) { + // This means that the attributes are not equal, but the + // actual values are the same - thus the order must have + // changed. This should result in a REPLACE_ATTRIBUTE operation. + myModifications.add(new ModificationItem( + DirContext.REPLACE_ATTRIBUTE, changedAttr)); + } + + modificationList.addAll(myModifications); + } + } + + private void collectModifications(Attribute originalAttr, + Attribute changedAttr, List modificationList) + throws NamingException { + + Attribute originalClone = (Attribute) originalAttr.clone(); + Attribute addedValuesAttribute = new BasicAttribute(originalAttr + .getID()); + + for (int i = 0; i < changedAttr.size(); i++) { + Object attributeValue = changedAttr.get(i); + if (!originalClone.remove(attributeValue)) { + addedValuesAttribute.add(attributeValue); + } + } + + // We have now traversed and removed all values from the original that + // were also present in the new values. The remaining values in the + // original must be the ones that were removed. + if (originalClone.size() > 0) { + modificationList.add(new ModificationItem( + DirContext.REMOVE_ATTRIBUTE, originalClone)); + } + + if (addedValuesAttribute.size() > 0) { + modificationList.add(new ModificationItem(DirContext.ADD_ATTRIBUTE, + addedValuesAttribute)); + } + } + + /** + * returns true if the attribute is empty. It is empty if a == null, size == + * 0 or get() == null or an exception if thrown when accessing the get + * method + */ + private boolean isEmptyAttribute(Attribute a) { + try { + return (a == null || a.size() == 0 || a.get() == null); + } + catch (NamingException e) { + return true; + } + } + + /** + * Compare the existing attribute name with the values on the + * array values. The order of the array must be the same order + * as the existing multivalued attribute. + *

+ * Also handles the case where the values have been reset to the original + * values after a previous change. For example, changing + * [a,b,c] to [a,b] and then back to + * [a,b,c] again must result in this method returning + * true so the first change can be overwritten with the latest + * change. + * + * @param name Name of the original multi-valued attribute. + * @param values Array of values to check if they have been changed. + * @return true if there has been a change compared to original attribute, + * or a previous update + */ + private boolean isChanged(String name, Object[] values, boolean orderMatters) { + + Attribute orig = originalAttrs.get(name); + Attribute prev = updatedAttrs.get(name); + + // values == null and values.length == 0 is treated the same way + boolean emptyNewValue = (values == null || values.length == 0); + + // Setting to empty --------------------- + if (emptyNewValue) { + // FALSE: if both are null, it is not changed (both don't exist) + // TRUE: if new value is null and old value exists (should be + // removed) + // TODO Also include prev in null check + // TODO Also check if there is a single null element + if (orig != null) { + return true; + } + return false; + } + + // NOT setting to empty ------------------- + + // TRUE if existing value is null + if (orig == null) { + return true; + } + + // TRUE if different length compared to original attributes + if (orig.size() != values.length) { + return true; + } + + // TRUE if different length compared to previously updated attributes + if (prev != null && prev.size() != values.length) { + return true; + } + + // Check contents of arrays + + // Order DOES matter, e.g. first names + try { + for (int i = 0; i < orig.size(); i++) { + Object obj = orig.get(i); + // TRUE if one value is not equal + if (!(obj instanceof String)) { + return true; + } + if (orderMatters) { + // check only the string with same index + if (!values[i].equals(obj)) { + return true; + } + } + else { + // check all strings + if (!ArrayUtils.contains(values, obj)) { + return true; + } + } + } + + } + catch (NamingException e) { + // TRUE if we can't access the value + return true; + } + + if (prev != null) { + // Also check against updatedAttrs, since there might have been + // a previous update + try { + for (int i = 0; i < prev.size(); i++) { + Object obj = prev.get(i); + // TRUE if one value is not equal + if (!(obj instanceof String)) { + return true; + } + if (orderMatters) { + // check only the string with same index + if (!values[i].equals(obj)) { + return true; + } + } + else { + // check all strings + if (!ArrayUtils.contains(values, obj)) { + return true; + } + } + } + + } + catch (NamingException e) { + // TRUE if we can't access the value + return true; + } + } + // FALSE since we have compared all values + return false; + } + + /** + * Checks if an entry has a specific attribute. + * + * This method simply calls exists(String) with the attribute name. + * + * @param attr the attribute to check. + * @return true if attribute exists in entry. + */ + protected final boolean exists(Attribute attr) { + return exists(attr.getID()); + } + + /** + * Checks if the attribute exists in this entry, either it was read or it + * has been added and update() has been called. + * + * @param attrId id of the attribute to check. + * @return true if the attribute exists in the entry. + */ + protected final boolean exists(String attrId) { + return originalAttrs.get(attrId) != null; + } + + /* + * @see + * org.springframework.ldap.support.DirContextOperations#getStringAttribute + * (java.lang.String) + */ + public String getStringAttribute(String name) { + return (String) getObjectAttribute(name); + } + + /* + * @see org.springframework.ldap.support.DirContextOperations#getObjectAttribute + * (java.lang.String) + */ + public Object getObjectAttribute(String name) { + Attribute oneAttr = originalAttrs.get(name); + if (oneAttr == null || oneAttr.size() == 0) { // LDAP-215 + return null; + } + try { + return oneAttr.get(); + } + catch (NamingException e) { + throw LdapUtils.convertLdapException(e); + } + } + + // LDAP-215 + /* (non-Javadoc) + * @see org.springframework.ldap.core.DirContextOperations#attributeExists(java.lang.String) + */ + public boolean attributeExists(String name) { + Attribute oneAttr = originalAttrs.get(name); + if (oneAttr == null) { + return false; + } else { + return true; + } + } + + /* + * @see + * org.springframework.ldap.support.DirContextOperations#setAttributeValue + * (java.lang.String, java.lang.Object) + */ + public void setAttributeValue(String name, Object value) { + // new entry + if (!updateMode && value != null) { + originalAttrs.put(name, value); + } + + // updating entry + if (updateMode) { + BasicAttribute attribute = new BasicAttribute(name); + if (value != null) { + attribute.add(value); + } + updatedAttrs.put(attribute); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.ldap.core.DirContextOperations#addAttributeValue( + * java.lang.String, java.lang.Object) + */ + public void addAttributeValue(String name, Object value) { + addAttributeValue(name, value, DONT_ADD_IF_DUPLICATE_EXISTS); + } + + public void addAttributeValue(String name, Object value, + boolean addIfDuplicateExists) { + if (!updateMode && value != null) { + Attribute attr = originalAttrs.get(name); + if (attr == null) { + originalAttrs.put(name, value); + } + else { + attr.add(value); + } + } + else if (updateMode) { + Attribute attr = updatedAttrs.get(name); + if (attr == null) { + if (originalAttrs.get(name) == null) { + // No match in the original attributes - + // add a new Attribute to updatedAttrs + updatedAttrs.put(name, value); + } + else { + // The attribute exists in the original attributes - clone + // that and add the new entry to it + attr = (Attribute) originalAttrs.get(name).clone(); + if (addIfDuplicateExists || !attr.contains(value)) { + attr.add(value); + } + updatedAttrs.put(attr); + } + } + else { + attr.add(value); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.ldap.core.DirContextOperations#removeAttributeValue + * (java.lang.String, java.lang.Object) + */ + public void removeAttributeValue(String name, Object value) { + if (!updateMode && value != null) { + Attribute attr = originalAttrs.get(name); + if (attr != null) { + attr.remove(value); + if (attr.size() == 0) { + originalAttrs.remove(name); + } + } + } + else if (updateMode) { + Attribute attr = updatedAttrs.get(name); + if (attr == null) { + if (originalAttrs.get(name) != null) { + attr = (Attribute) originalAttrs.get(name).clone(); + attr.remove(value); + updatedAttrs.put(attr); + } + } + else { + attr.remove(value); + } + } + } + + /* + * @see + * org.springframework.ldap.support.DirContextOperations#setAttributeValues + * (java.lang.String, java.lang.Object[]) + */ + public void setAttributeValues(String name, Object[] values) { + setAttributeValues(name, values, ORDER_DOESNT_MATTER); + } + + /* + * @see + * org.springframework.ldap.support.DirContextOperations#setAttributeValues + * (java.lang.String, java.lang.Object[], boolean) + */ + public void setAttributeValues(String name, Object[] values, + boolean orderMatters) { + Attribute a = new BasicAttribute(name, orderMatters); + + for (int i = 0; values != null && i < values.length; i++) { + a.add(values[i]); + } + + // only change the original attribute if not in update mode + if (!updateMode && values != null && values.length > 0) { + // don't save empty arrays + originalAttrs.put(a); + } + + // possible to set an already existing attribute to an empty array + if (updateMode && isChanged(name, values, orderMatters)) { + updatedAttrs.put(a); + } + } + + /* + * @see org.springframework.ldap.support.DirContextOperations#update() + */ + public void update() { + NamingEnumeration attributesEnumeration = null; + + try { + attributesEnumeration = updatedAttrs.getAll(); + + // find what to update + while (attributesEnumeration.hasMore()) { + Attribute a = (Attribute) attributesEnumeration.next(); + + // if it does not exist it should be added + if (isEmptyAttribute(a)) { + originalAttrs.remove(a.getID()); + } + else { + // Otherwise it should be set. + originalAttrs.put(a); + } + } + } + catch (NamingException e) { + throw LdapUtils.convertLdapException(e); + } + finally { + closeNamingEnumeration(attributesEnumeration); + } + + // Reset the attributes to be updated + updatedAttrs = new BasicAttributes(true); + } + + /* + * @see + * org.springframework.ldap.core.DirContextOperations#getStringAttributes + * (java.lang.String) + */ + public String[] getStringAttributes(String name) { + try { + return (String[]) collectAttributeValuesAsList(name).toArray( + new String[0]); + } + catch (NoSuchAttributeException e) { + // The attribute does not exist - contract says to return null. + return null; + } + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.ldap.core.DirContextOperations#getObjectAttributes + * (java.lang.String) + */ + public Object[] getObjectAttributes(String name) { + try { + return collectAttributeValuesAsList(name).toArray(new Object[0]); + } + catch (NoSuchAttributeException e) { + // The attribute does not exist - contract says to return null. + return null; + } + } + + private List collectAttributeValuesAsList(String name) { + List list = new LinkedList(); + LdapUtils.collectAttributeValues(originalAttrs, name, list); + return list; + } + + /* + * @seeorg.springframework.ldap.support.DirContextOperations# + * getAttributeSortedStringSet(java.lang.String) + */ + public SortedSet getAttributeSortedStringSet(String name) { + try { + TreeSet attrSet = new TreeSet(); + LdapUtils.collectAttributeValues(originalAttrs, name, attrSet); + return attrSet; + } + catch (NoSuchAttributeException e) { + // The attribute does not exist - contract says to return null. + return null; + } + } + + /** + * Set the supplied attribute. + * + * @param attribute the attribute to set. + */ + public void setAttribute(Attribute attribute) { + if (!updateMode) { + originalAttrs.put(attribute); + } + else { + updatedAttrs.put(attribute); + } + } + + /** + * Get all attributes. + * + * @return all attributes. + */ + public Attributes getAttributes() { + return originalAttrs; + } + + /** + * @see javax.naming.directory.DirContext#getAttributes(Name) + */ + public Attributes getAttributes(Name name) throws NamingException { + return getAttributes(name.toString()); + } + + /** + * @see javax.naming.directory.DirContext#getAttributes(String) + */ + public Attributes getAttributes(String name) throws NamingException { + if (StringUtils.hasLength(name)) { + throw new NameNotFoundException(); + } + return (Attributes) originalAttrs.clone(); + } + + /** + * @see javax.naming.directory.DirContext#getAttributes(Name, String[]) + */ + public Attributes getAttributes(Name name, String[] attrIds) + throws NamingException { + return getAttributes(name.toString(), attrIds); + } + + /** + * @see javax.naming.directory.DirContext#getAttributes(String, String[]) + */ + public Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + if (StringUtils.hasLength(name)) { + throw new NameNotFoundException(); + } + + Attributes a = new BasicAttributes(true); + Attribute target; + for (int i = 0; i < attrIds.length; i++) { + target = originalAttrs.get(attrIds[i]); + if (target != null) { + a.put(target); + } + } + + return a; + } + + /** + * @see javax.naming.directory.DirContext#modifyAttributes(javax.naming.Name, + * int, javax.naming.directory.Attributes) + */ + public void modifyAttributes(Name name, int modOp, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#modifyAttributes(String, int, + * Attributes) + */ + public void modifyAttributes(String name, int modOp, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#modifyAttributes(Name, + * ModificationItem[]) + */ + public void modifyAttributes(Name name, ModificationItem[] mods) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#modifyAttributes(String, + * ModificationItem[]) + */ + public void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#bind(Name, Object, Attributes) + */ + public void bind(Name name, Object obj, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#bind(String, Object, Attributes) + */ + public void bind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#rebind(Name, Object, Attributes) + */ + public void rebind(Name name, Object obj, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#rebind(String, Object, Attributes) + */ + public void rebind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#createSubcontext(Name, Attributes) + */ + public DirContext createSubcontext(Name name, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#createSubcontext(String, + * Attributes) + */ + public DirContext createSubcontext(String name, Attributes attrs) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#getSchema(Name) + */ + public DirContext getSchema(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#getSchema(String) + */ + public DirContext getSchema(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#getSchemaClassDefinition(Name) + */ + public DirContext getSchemaClassDefinition(Name name) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#getSchemaClassDefinition(String) + */ + public DirContext getSchemaClassDefinition(String name) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(Name, Attributes, String[]) + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes, + String[] attributesToReturn) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(String, Attributes, + * String[]) + */ + public NamingEnumeration search(String name, Attributes matchingAttributes, + String[] attributesToReturn) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(Name, Attributes) + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(String, Attributes) + */ + public NamingEnumeration search(String name, Attributes matchingAttributes) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(Name, String, + * SearchControls) + */ + public NamingEnumeration search(Name name, String filter, + SearchControls cons) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(String, String, + * SearchControls) + */ + public NamingEnumeration search(String name, String filter, + SearchControls cons) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(Name, String, Object[], + * SearchControls) + */ + public NamingEnumeration search(Name name, String filterExpr, + Object[] filterArgs, SearchControls cons) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.directory.DirContext#search(String, String, Object[], + * SearchControls) + */ + public NamingEnumeration search(String name, String filterExpr, + Object[] filterArgs, SearchControls cons) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#lookup(Name) + */ + public Object lookup(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#lookup(String) + */ + public Object lookup(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#bind(Name, Object) + */ + public void bind(Name name, Object obj) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#bind(String, Object) + */ + public void bind(String name, Object obj) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#rebind(Name, Object) + */ + public void rebind(Name name, Object obj) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#rebind(String, Object) + */ + public void rebind(String name, Object obj) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#unbind(Name) + */ + public void unbind(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#unbind(String) + */ + public void unbind(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#rename(Name, Name) + */ + public void rename(Name oldName, Name newName) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#rename(String, String) + */ + public void rename(String oldName, String newName) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#list(Name) + */ + public NamingEnumeration list(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#list(String) + */ + public NamingEnumeration list(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#listBindings(Name) + */ + public NamingEnumeration listBindings(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#listBindings(String) + */ + public NamingEnumeration listBindings(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#destroySubcontext(Name) + */ + public void destroySubcontext(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#destroySubcontext(String) + */ + public void destroySubcontext(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#createSubcontext(Name) + */ + public Context createSubcontext(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#createSubcontext(String) + */ + public Context createSubcontext(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#lookupLink(Name) + */ + public Object lookupLink(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#lookupLink(String) + */ + public Object lookupLink(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#getNameParser(Name) + */ + public NameParser getNameParser(Name name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#getNameParser(String) + */ + public NameParser getNameParser(String name) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#composeName(Name, Name) + */ + public Name composeName(Name name, Name prefix) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#composeName(String, String) + */ + public String composeName(String name, String prefix) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#addToEnvironment(String, Object) + */ + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#removeFromEnvironment(String) + */ + public Object removeFromEnvironment(String propName) throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#getEnvironment() + */ + public Hashtable getEnvironment() throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#close() + */ + public void close() throws NamingException { + throw new UnsupportedOperationException("Not implemented."); + } + + /** + * @see javax.naming.Context#getNameInNamespace() + */ + public String getNameInNamespace() { + DistinguishedName result = new DistinguishedName(dn); + result.prepend(base); + return result.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.support.DirContextOperations#getDn() + */ + public Name getDn() { + return new DistinguishedName(dn); + } + + /* + * (non-Javadoc) + * + * @see + * org.springframework.ldap.support.DirContextOperations#setDn(javax.naming + * .Name) + */ + public final void setDn(Name dn) { + if (!updateMode) { + this.dn = new DistinguishedName(dn.toString()); + } + else { + throw new IllegalStateException( + "Not possible to call setDn() on a DirContextAdapter in update mode"); + } + + } + + /** + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + // A subclass with identical values should NOT be considered equal. + // EqualsBuilder in commons-lang cannot handle subclasses correctly. + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + return EqualsBuilder.reflectionEquals(this, obj); + } + + /** + * @see Object#hashCode() + */ + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append(getClass().getName()); + buf.append(":"); + if (dn != null) { + buf.append(" dn=" + dn); + } + buf.append(" {"); + + try { + for (NamingEnumeration i = originalAttrs.getAll(); i.hasMore();) { + Attribute attribute = (Attribute) i.next(); + if (attribute.size() == 1) { + buf.append(attribute.getID()); + buf.append('='); + buf.append(attribute.get()); + } + else { + for (int j = 0; j < attribute.size(); j++) { + if (j > 0) { + buf.append(", "); + } + buf.append(attribute.getID()); + buf.append('['); + buf.append(j); + buf.append("]="); + buf.append(attribute.get(j)); + } + } + + if (i.hasMore()) { + buf.append(", "); + } + } + } + catch (NamingException e) { + log.warn("Error in toString()"); + } + buf.append('}'); + + return buf.toString(); + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.core.DirContextOperations#getReferralUrl() + */ + public String getReferralUrl() { + return referralUrl; + } + + /* + * (non-Javadoc) + * + * @see org.springframework.ldap.core.DirContextOperations#isReferral() + */ + public boolean isReferral() { + return StringUtils.hasLength(referralUrl); + } + +} diff --git a/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java b/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java index c748f7d8..77b72a1c 100644 --- a/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java +++ b/core/src/main/java/org/springframework/ldap/core/DirContextOperations.java @@ -1,246 +1,260 @@ -/* - * Copyright 2005-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ldap.core; - -import java.util.SortedSet; - -import javax.naming.Name; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; - -/** - * Interface for DirContextAdapter. - * - * @author Mattias Hellborg Arthursson - * @see DirContextAdapter - */ -public interface DirContextOperations extends DirContext, - AttributeModificationsAware { - - /** - * Gets the update mode. An entry in update mode will keep track of its - * modifications so that they can be retrieved using - * {@link AttributeModificationsAware#getModificationItems()}. The update - * mode should be true for a new entry and true - * for an existing entry that is being updated. - * - * @return update mode. - */ - boolean isUpdateMode(); - - /** - * Creates a String array of the names of the attributes which have been - * changed. - * - * If this is a new entry, all set entries will be in the list. If this is - * an updated entry, only changed and removed entries will be in the array. - * - * @return Array of String - */ - String[] getNamesOfModifiedAttributes(); - - /** - * Get the value of a String attribute. If more than one attribute value - * exists for the specified attribute, only the first one will be returned. - * - * @param name name of the attribute. - * @return the value of the attribute. - * @throws ClassCastException if the value of the entry is not a String. - */ - String getStringAttribute(String name); - - /** - * Get the value of an Object attribute. If more than one attribute value - * exists for the specified attribute, only the first one will be returned. - * - * @param name name of the attribute. - * @return the attribute value as an object if it exists, or - * null otherwise. - */ - Object getObjectAttribute(String name); - - /** - * Set the with the name name to the value. - * - * @param name name of the attribute. - * @param value value to set the attribute to. - */ - public void setAttributeValue(String name, Object value); - - /** - * Sets a multivalue attribute, disregarding the order of the values. - * - * If value is null or value.length == 0 then the attribute will be removed. - * - * If update mode, changes will be made only if the array has more or less - * objects or if one or more object has changed. Reordering the objects will - * not cause an update. - * - * @param name The id of the attribute. - * @param values Attribute values. - */ - void setAttributeValues(String name, Object[] values); - - /** - * Sets a multivalue attribute. - * - * If value is null or value.length == 0 then the attribute will be removed. - * - * If update mode, changes will be made if the array has more or less - * objects or if one or more string has changed. - * - * Reordering the objects will only cause an update if orderMatters is set - * to true. - * - * @param name The id of the attribute. - * @param values Attribute values. - * @param orderMatters If true, it will be changed even if data - * was just reordered. - */ - void setAttributeValues(String name, Object[] values, boolean orderMatters); - - /** - * Add a value to the Attribute with the specified name. If the Attribute - * doesn't exist it will be created. This method makes sure that the there - * will be no duplicates of an added value - it the value exists it will not - * be added again. - * - * @param name the name of the Attribute to which the specified value should - * be added. - * @param value the Attribute value to add. - */ - void addAttributeValue(String name, Object value); - - /** - * Add a value to the Attribute with the specified name. If the Attribute - * doesn't exist it will be created. The addIfDuplicateExists - * parameter controls the handling of duplicates. It false, - * this method makes sure that the there will be no duplicates of an added - * value - it the value exists it will not be added again. - * - * @param name the name of the Attribute to which the specified value should - * be added. - * @param value the Attribute value to add. - * @param addIfDuplicateExists true will add the value - * regardless of whether there is an identical value already, allowing for - * duplicate attribute values; false will not add the value if - * it already exists. - */ - void addAttributeValue(String name, Object value, - boolean addIfDuplicateExists); - - /** - * Remove a value from the Attribute with the specified name. If the - * Attribute doesn't exist, do nothing. - * - * @param name the name of the Attribute from which the specified value - * should be removed. - * @param value the value to remove. - */ - void removeAttributeValue(String name, Object value); - - /** - * Update the attributes.This will mean that the getters ( - * getStringAttribute methods) will return the updated values, - * and the modifications will be forgotten (i.e. - * {@link AttributeModificationsAware#getModificationItems()} will return an - * empty array. - */ - void update(); - - /** - * Get all values of a String attribute. - * - * @param name name of the attribute. - * @return a (possibly empty) array containing all registered values of the - * attribute as Strings if the attribute is defined or null - * otherwise. - * @throws ArrayStoreException if any of the attribute values is not a - * String. - */ - String[] getStringAttributes(String name); - - /** - * Get all values of an Object attribute. - * - * @param name name of the attribute. - * @return a (possibly empty) array containing all registered values of the - * attribute if the attribute is defined or null otherwise. - * @since 1.3 - */ - Object[] getObjectAttributes(String name); - - /** - * Get all String values of the attribute as a SortedSet. - * - * @param name name of the attribute. - * @return a SortedSet containing all values of the attribute, - * or null if the attribute does not exist. - */ - SortedSet getAttributeSortedStringSet(String name); - - /** - * Returns the DN relative to the base path. - * - * @return The distinguished name of the current context. - * - * @see DirContextAdapter#getNameInNamespace() - */ - Name getDn(); - - /** - * Set the dn of this entry. - * - * @param dn the dn. - */ - void setDn(Name dn); - - /* - * (non-Javadoc) - * - * @see javax.naming.Context#getNameInNamespace() - */ - String getNameInNamespace(); - - /** - * If this instance results from a referral, this method returns the url of - * the referred server. - * - * @return The url of the referred server, e.g. - * ldap://localhost:389, or the empty string if this is not a - * referral. - * @since 1.3 - */ - String getReferralUrl(); - - /** - * Checks whether this instance results from a referral. - * - * @return true if this instance results from a referral, - * false otherwise. - * @since 1.3 - */ - boolean isReferral(); - - /** - * Get all the Attributes. - * - * @return all the Attributes. - * @since 1.3 - */ - Attributes getAttributes(); -} \ No newline at end of file +/* + * Copyright 2005-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ldap.core; + +import java.util.SortedSet; + +import javax.naming.Name; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; + +/** + * Interface for DirContextAdapter. + * + * @author Mattias Hellborg Arthursson + * @see DirContextAdapter + */ +public interface DirContextOperations extends DirContext, + AttributeModificationsAware { + + /** + * Gets the update mode. An entry in update mode will keep track of its + * modifications so that they can be retrieved using + * {@link AttributeModificationsAware#getModificationItems()}. The update + * mode should be true for a new entry and true + * for an existing entry that is being updated. + * + * @return update mode. + */ + boolean isUpdateMode(); + + /** + * Creates a String array of the names of the attributes which have been + * changed. + * + * If this is a new entry, all set entries will be in the list. If this is + * an updated entry, only changed and removed entries will be in the array. + * + * @return Array of String + */ + String[] getNamesOfModifiedAttributes(); + + /** + * Get the value of a String attribute. If more than one attribute value + * exists for the specified attribute, only the first one will be returned. + * If an attribute has no value, null will be returned. + * + * @param name name of the attribute. + * @return the value of the attribute if it exists, or null if + * the attribute doesn't exist or if it exists but with no value. + * @throws ClassCastException if the value of the entry is not a String. + */ + String getStringAttribute(String name); + + /** + * Get the value of an Object attribute. If more than one attribute value + * exists for the specified attribute, only the first one will be returned. + * If an attribute has no value, null will be returned. + * + * @param name name of the attribute. + * @return the attribute value as an object if it exists, or + * null if the attribute doesn't exist or if it exists but with + * no value. + */ + Object getObjectAttribute(String name); + + /** + * Check if an Object attribute exists, regardless of whether it has a value + * or not. + * + * @param name name of the attribute + * @return true if the attribute exists, false + * otherwise + */ + boolean attributeExists(String name); + + /** + * Set the with the name name to the value. + * + * @param name name of the attribute. + * @param value value to set the attribute to. + */ + public void setAttributeValue(String name, Object value); + + /** + * Sets a multivalue attribute, disregarding the order of the values. + * + * If value is null or value.length == 0 then the attribute will be removed. + * + * If update mode, changes will be made only if the array has more or less + * objects or if one or more object has changed. Reordering the objects will + * not cause an update. + * + * @param name The id of the attribute. + * @param values Attribute values. + */ + void setAttributeValues(String name, Object[] values); + + /** + * Sets a multivalue attribute. + * + * If value is null or value.length == 0 then the attribute will be removed. + * + * If update mode, changes will be made if the array has more or less + * objects or if one or more string has changed. + * + * Reordering the objects will only cause an update if orderMatters is set + * to true. + * + * @param name The id of the attribute. + * @param values Attribute values. + * @param orderMatters If true, it will be changed even if data + * was just reordered. + */ + void setAttributeValues(String name, Object[] values, boolean orderMatters); + + /** + * Add a value to the Attribute with the specified name. If the Attribute + * doesn't exist it will be created. This method makes sure that the there + * will be no duplicates of an added value - it the value exists it will not + * be added again. + * + * @param name the name of the Attribute to which the specified value should + * be added. + * @param value the Attribute value to add. + */ + void addAttributeValue(String name, Object value); + + /** + * Add a value to the Attribute with the specified name. If the Attribute + * doesn't exist it will be created. The addIfDuplicateExists + * parameter controls the handling of duplicates. It false, + * this method makes sure that the there will be no duplicates of an added + * value - it the value exists it will not be added again. + * + * @param name the name of the Attribute to which the specified value should + * be added. + * @param value the Attribute value to add. + * @param addIfDuplicateExists true will add the value + * regardless of whether there is an identical value already, allowing for + * duplicate attribute values; false will not add the value if + * it already exists. + */ + void addAttributeValue(String name, Object value, + boolean addIfDuplicateExists); + + /** + * Remove a value from the Attribute with the specified name. If the + * Attribute doesn't exist, do nothing. + * + * @param name the name of the Attribute from which the specified value + * should be removed. + * @param value the value to remove. + */ + void removeAttributeValue(String name, Object value); + + /** + * Update the attributes.This will mean that the getters ( + * getStringAttribute methods) will return the updated values, + * and the modifications will be forgotten (i.e. + * {@link AttributeModificationsAware#getModificationItems()} will return an + * empty array. + */ + void update(); + + /** + * Get all values of a String attribute. + * + * @param name name of the attribute. + * @return a (possibly empty) array containing all registered values of the + * attribute as Strings if the attribute is defined or null + * otherwise. + * @throws ArrayStoreException if any of the attribute values is not a + * String. + */ + String[] getStringAttributes(String name); + + /** + * Get all values of an Object attribute. + * + * @param name name of the attribute. + * @return a (possibly empty) array containing all registered values of the + * attribute if the attribute is defined or null otherwise. + * @since 1.3 + */ + Object[] getObjectAttributes(String name); + + /** + * Get all String values of the attribute as a SortedSet. + * + * @param name name of the attribute. + * @return a SortedSet containing all values of the attribute, + * or null if the attribute does not exist. + */ + SortedSet getAttributeSortedStringSet(String name); + + /** + * Returns the DN relative to the base path. + * + * @return The distinguished name of the current context. + * + * @see DirContextAdapter#getNameInNamespace() + */ + Name getDn(); + + /** + * Set the dn of this entry. + * + * @param dn the dn. + */ + void setDn(Name dn); + + /* + * (non-Javadoc) + * + * @see javax.naming.Context#getNameInNamespace() + */ + String getNameInNamespace(); + + /** + * If this instance results from a referral, this method returns the url of + * the referred server. + * + * @return The url of the referred server, e.g. + * ldap://localhost:389, or the empty string if this is not a + * referral. + * @since 1.3 + */ + String getReferralUrl(); + + /** + * Checks whether this instance results from a referral. + * + * @return true if this instance results from a referral, + * false otherwise. + * @since 1.3 + */ + boolean isReferral(); + + /** + * Get all the Attributes. + * + * @return all the Attributes. + * @since 1.3 + */ + Attributes getAttributes(); +} diff --git a/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java b/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java index d0350ed6..4c029e75 100644 --- a/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java +++ b/core/src/test/java/org/springframework/ldap/core/DirContextAdapterTest.java @@ -1,1140 +1,1158 @@ -/* - * Copyright 2005-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ldap.core; - -import java.util.Iterator; -import java.util.SortedSet; - -import javax.naming.CompositeName; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.BasicAttribute; -import javax.naming.directory.BasicAttributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; - -import junit.framework.TestCase; - -/** - * Tests the DirContextAdapter class. - * - * @author Andreas Ronge - * @author Mattias Hellborg Arthursson - * @author Ulrik Sandberg - */ -public class DirContextAdapterTest extends TestCase { - private static final DistinguishedName BASE_NAME = new DistinguishedName( - "dc=jayway, dc=se"); - - private static final DistinguishedName DUMMY_NAME = new DistinguishedName( - "c=SE, dc=jayway, dc=se"); - - private DirContextAdapter tested; - - protected void setUp() throws Exception { - super.setUp(); - tested = new DirContextAdapter(); - } - - protected void tearDown() throws Exception { - super.tearDown(); - } - - public void testSetUpdateMode() throws Exception { - assertFalse(tested.isUpdateMode()); - tested.setUpdateMode(true); - assertTrue(tested.isUpdateMode()); - tested.setUpdateMode(false); - assertFalse(tested.isUpdateMode()); - } - - public void testGetModificationItems() throws Exception { - ModificationItem[] items = tested.getModificationItems(); - assertEquals(0, items.length); - tested.setUpdateMode(true); - assertEquals(0, items.length); - } - - public void testAlwaysReplace() throws Exception { - ModificationItem[] items = tested.getModificationItems(); - assertEquals(0, items.length); - tested.setUpdateMode(true); - assertEquals(0, items.length); - } - - public void testGetStringAttributeNotExists() throws Exception { - String s = tested.getStringAttribute("does not exist"); - assertNull(s); - } - - public void testGetStringAttributeDoesExistButWithNoValue() throws Exception { - final Attributes attrs = new BasicAttributes(); - attrs.put(new BasicAttribute("abc")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - String s = tested.getStringAttribute("abc"); - assertNull(s); - } - - public void testGetStringAttributeExists() throws Exception { - final Attributes attrs = new BasicAttributes(); - attrs.put(new BasicAttribute("abc", "def")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - String s = tested.getStringAttribute("abc"); - assertEquals("def", s); - } - - public void testGetStringAttributesExists() throws Exception { - final Attributes attrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("234"); - attrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - String s[] = tested.getStringAttributes("abc"); - assertEquals("123", s[0]); - assertEquals("234", s[1]); - assertEquals(2, s.length); - } - - public void testGetStringAttributesExistsWithInvalidType() throws Exception { - final Attributes attrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add(new Object()); - attrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - try { - tested.getStringAttributes("abc"); - fail("ClassCastException expected"); - } - catch (ArrayStoreException expected) { - assertTrue(true); - } - } - - public void testGetStringAttributesExistsEmpty() throws Exception { - final Attributes attrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - attrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - String s[] = tested.getStringAttributes("abc"); - assertNotNull(s); - assertEquals(0, s.length); - } - - public void testGetStringAttributesNotExists() throws Exception { - String s[] = tested.getStringAttributes("abc"); - assertNull(s); - } - - public void testGetAttributesSortedStringSetExists() throws Exception { - final Attributes attrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("234"); - attrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - SortedSet s = tested.getAttributeSortedStringSet("abc"); - assertNotNull(s); - assertEquals(2, s.size()); - Iterator it = s.iterator(); - assertEquals("123", it.next()); - assertEquals("234", it.next()); - } - - public void testGetAttributesSortedStringSetNotExists() throws Exception { - final Attributes attrs = new BasicAttributes(); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(attrs, null); - } - } - tested = new TestableDirContextAdapter(); - SortedSet s = tested.getAttributeSortedStringSet("abc"); - assertNull(s); - } - - public void testAddAttributeValue() throws NamingException { - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals("123", (String) attr.get()); - } - - public void testAddAttributeValueAttributeWithOtherValueExists() - throws NamingException { - tested.setAttribute(new BasicAttribute("abc", "321")); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals("321", (String) attr.get(0)); - assertEquals("123", (String) attr.get(1)); - } - - public void testAddAttributeValueAttributeWithSameValueExists() - throws NamingException { - tested.setAttribute(new BasicAttribute("abc", "123")); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals(1, attr.size()); - assertEquals("123", (String) attr.get(0)); - } - - public void testAddAttributeValueInUpdateMode() throws NamingException { - tested.setUpdateMode(true); - tested.addAttributeValue("abc", "123"); - - // Perform test - Attributes attrs = tested.getAttributes(); - assertNull(attrs.get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute attribute = modificationItems[0].getAttribute(); - assertEquals("abc", attribute.getID()); - assertEquals("123", attribute.get()); - } - - public void testAddAttributeValueInUpdateModeAttributeWhenOtherValueExistsInOrigAttrs() - throws NamingException { - - tested.setAttribute(new BasicAttribute("abc", "321")); - tested.setUpdateMode(true); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - assertNotNull(attrs.get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute attribute = modificationItems[0].getAttribute(); - assertEquals(1, attribute.size()); - assertEquals("abc", attribute.getID()); - assertEquals("123", attribute.get()); - } - - public void testGetModificationItemsOnAddAttributeValueInUpdateModeAttributeWhenSameValueExistsInOrigAttrs() - throws NamingException { - - tested.setAttribute(new BasicAttribute("abc", "123")); - tested.setUpdateMode(true); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - assertNotNull(attrs.get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(0, modificationItems.length); - } - - public void testAddAttributeValueInUpdateModeAttributeWithOtherValueExistsInUpdAttrs() - throws NamingException { - tested.setUpdateMode(true); - tested.setAttributeValue("abc", "321"); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - assertNull(attrs.get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute attribute = modificationItems[0].getAttribute(); - assertEquals("abc", attribute.getID()); - assertEquals("321", attribute.get(0)); - assertEquals("123", attribute.get(1)); - } - - public void testAddAttributeValueInUpdateModeAttributeWithSameValueExistsInUpdAttrs() - throws NamingException { - tested.setUpdateMode(true); - tested.setAttributeValue("abc", "123"); - - // Perform test - tested.addAttributeValue("abc", "123"); - - Attributes attrs = tested.getAttributes(); - assertNull(attrs.get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute attribute = modificationItems[0].getAttribute(); - assertEquals(1, attribute.size()); - assertEquals("abc", attribute.getID()); - assertEquals("123", attribute.get()); - } - - public void testRemoveAttributeValueAttributeDoesntExist() { - // Perform test - tested.removeAttributeValue("abc", "123"); - - Attributes attributes = tested.getAttributes(); - assertNull(attributes.get("abc")); - } - - public void testRemoveAttributeValueAttributeWithOtherValueExists() - throws NamingException { - tested.setAttribute(new BasicAttribute("abc", "321")); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - Attributes attributes = tested.getAttributes(); - Attribute attr = attributes.get("abc"); - assertNotNull(attr); - assertEquals(1, attr.size()); - assertEquals("321", attr.get()); - } - - public void testRemoveAttributeValueAttributeWithSameValueExists() { - tested.setAttribute(new BasicAttribute("abc", "123")); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - Attributes attributes = tested.getAttributes(); - Attribute attr = attributes.get("abc"); - assertNull(attr); - } - - public void testRemoveAttributeValueAttributeWithOtherAndSameValueExists() - throws NamingException { - BasicAttribute basicAttribute = new BasicAttribute("abc"); - basicAttribute.add("123"); - basicAttribute.add("321"); - tested.setAttribute(basicAttribute); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - Attributes attributes = tested.getAttributes(); - Attribute attr = attributes.get("abc"); - assertNotNull(attr); - assertEquals(1, attr.size()); - assertEquals("321", attr.get()); - } - - public void testRemoveAttributeValueInUpdateMode() { - tested.setUpdateMode(true); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - assertNull(tested.getAttributes().get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(0, modificationItems.length); - } - - public void testRemoveAttributeValueInUpdateModeSameValueExistsInUpdatedAttrs() { - tested.setUpdateMode(true); - tested.setAttributeValue("abc", "123"); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - assertNull(tested.getAttributes().get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(0, modificationItems.length); - } - - public void testRemoveAttributeValueInUpdateModeOtherValueExistsInUpdatedAttrs() - throws NamingException { - tested.setUpdateMode(true); - tested.setAttributeValue("abc", "321"); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - assertNull(tested.getAttributes().get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute modificationAttribute = modificationItems[0].getAttribute(); - assertEquals("abc", modificationAttribute.getID()); - assertEquals(1, modificationAttribute.size()); - assertEquals("321", modificationAttribute.get()); - } - - public void testRemoveAttributeValueInUpdateModeOtherAndSameValueExistsInUpdatedAttrs() - throws NamingException { - tested.setUpdateMode(true); - tested.setAttributeValues("abc", new String[] { "321", "123" }); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - assertNull(tested.getAttributes().get("abc")); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute modificationAttribute = modificationItems[0].getAttribute(); - assertEquals("abc", modificationAttribute.getID()); - assertEquals(1, modificationAttribute.size()); - } - - public void testRemoveAttributeValueInUpdateModeSameValueExistsInOrigAttrs() { - tested.setAttribute(new BasicAttribute("abc", "123")); - tested.setUpdateMode(true); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute modificationAttribute = modificationItems[0].getAttribute(); - assertEquals("abc", modificationAttribute.getID()); - assertEquals(0, modificationAttribute.size()); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - } - - public void testRemoveAttributeValueInUpdateModeSameAndOtherValueExistsInOrigAttrs() - throws NamingException { - BasicAttribute basicAttribute = new BasicAttribute("abc"); - basicAttribute.add("123"); - basicAttribute.add("321"); - tested.setAttribute(basicAttribute); - tested.setUpdateMode(true); - - // Perform test - tested.removeAttributeValue("abc", "123"); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - Attribute modificationAttribute = modificationItems[0].getAttribute(); - assertEquals("abc", modificationAttribute.getID()); - assertEquals(1, modificationAttribute.size()); - assertEquals("123", modificationAttribute.get()); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - } - - public void testSetStringAttribute() throws Exception { - assertFalse(tested.isUpdateMode()); - tested.setAttributeValue("abc", "123"); - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals("123", (String) attr.get()); - } - - public void testSetStringAttributeNull() throws Exception { - assertFalse(tested.isUpdateMode()); - tested.setAttributeValue("abc", null); - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertNull(attr); - } - - public void testAddAttribute() throws Exception { - tested.setUpdateMode(true); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValue("abc", "123"); - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertNull(attr); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.ADD_ATTRIBUTE, mods[0].getModificationOp()); - attr = mods[0].getAttribute(); - assertEquals("123", (String) attr.get()); - - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(1, modNames.length); - assertEquals("abc", modNames[0]); - - tested.update(); - mods = tested.getModificationItems(); - assertEquals(0, mods.length); - modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - attrs = tested.getAttributes(); - attr = attrs.get("abc"); - assertEquals("123", (String) attr.get()); - } - - public void testGetDn() throws Exception { - DirContextAdapter tested = new DirContextAdapter(DUMMY_NAME); - Name result = tested.getDn(); - assertEquals(DUMMY_NAME, result); - } - - public void testGetDn_BasePath() { - DirContextAdapter tested = new DirContextAdapter(null, DUMMY_NAME, - BASE_NAME); - Name result = tested.getDn(); - assertEquals(DUMMY_NAME, result); - } - - public void testGetNameInNamespace() { - DirContextAdapter tested = new DirContextAdapter(DUMMY_NAME); - String result = tested.getNameInNamespace(); - assertEquals(DUMMY_NAME.toString(), result); - } - - public void testGetNameInNamespace_BasePath() { - DirContextAdapter tested = new DirContextAdapter(null, - new DistinguishedName("c=SE"), BASE_NAME); - String result = tested.getNameInNamespace(); - assertEquals(DUMMY_NAME.toString(), result); - } - - public void testAddMultiAttributes() throws Exception { - tested.setUpdateMode(true); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123", "456" }); - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertNull(attr); - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.ADD_ATTRIBUTE, mods[0].getModificationOp()); - attr = mods[0].getAttribute(); - assertEquals(2, attr.size()); - assertEquals("123", (String) attr.get(0)); - assertEquals("456", (String) attr.get(1)); - - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(1, modNames.length); - assertEquals("abc", modNames[0]); - - tested.update(); - mods = tested.getModificationItems(); - assertEquals(0, mods.length); - modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - attrs = tested.getAttributes(); - attr = attrs.get("abc"); - assertEquals("123", (String) attr.get(0)); - assertEquals("456", (String) attr.get(1)); - } - - public void testRemoveAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - fixtureAttrs.put(new BasicAttribute("abc", "123")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - - tested.setUpdateMode(true); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValue("abc", null); - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals("123", (String) attr.get()); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REMOVE_ATTRIBUTE, mods[0].getModificationOp()); - attr = mods[0].getAttribute(); - assertEquals("abc", (String) attr.getID()); - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(1, modNames.length); - assertEquals("abc", modNames[0]); - - tested.update(); - mods = tested.getModificationItems(); - assertEquals(0, mods.length); - modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - attrs = tested.getAttributes(); - attr = attrs.get("abc"); - assertNull(attr); - } - - public void testRemoveMultiAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute abc = new BasicAttribute("abc"); - abc.add("123"); - abc.add("456"); - fixtureAttrs.put(abc); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - - tested.setUpdateMode(true); - tested.setAttributeValues("abc", new String[] {}); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REMOVE_ATTRIBUTE, mods[0].getModificationOp()); - Attribute attr = mods[0].getAttribute(); - assertEquals("abc", (String) attr.getID()); - assertEquals(0, attr.size()); - } - - public void testChangeAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - fixtureAttrs.put(new BasicAttribute("abc", "123")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - tested.setAttributeValue("abc", "234"); // change - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); - Attribute attr = mods[0].getAttribute(); - assertEquals("abc", (String) attr.getID()); - assertEquals("234", (String) attr.get()); - } - - public void testNoChangeAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - fixtureAttrs.put(new BasicAttribute("abc", "123")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValue("abc", "123"); // change - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(0, mods.length); - } - - public void testNoChangeMultiAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123", "qwe" }); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(0, mods.length); - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - } - - public void testNoChangeMultiAttributeOrderDoesNotMatter() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - tested.setAttributeValues("abc", new String[] { "qwe", "123" }); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(0, mods.length); - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - } - - public void testChangeMultiAttributeOrderDoesMatter() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "qwe", "123" }, true); - - // change - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); - Attribute attr = mods[0].getAttribute(); - assertEquals("qwe", attr.get(0)); - assertEquals("123", attr.get(1)); - } - - /** - * Test case corresponding to LDAP-96 in Spring Jira. - * http://jira.springframework.org/browse/LDAP-96 - */ - public void testChangeMultiAttributeOrderDoesMatterLDAP96() - throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("title"); - multi.add("Juergen"); - multi.add("George"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("title", new String[] { "Jim", "George", - "Juergen" }, true); - - // change - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); - Attribute attr = mods[0].getAttribute(); - assertEquals("Jim", attr.get(0)); - assertEquals("George", attr.get(1)); - assertEquals("Juergen", attr.get(2)); - } - - public void testChangeMultiAttribute_AddValue() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested - .setAttributeValues("abc", - new String[] { "123", "qwe", "klytt" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - assertEquals(DirContext.ADD_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - assertEquals("klytt", modificationItems[0].getAttribute().get()); - } - - public void testChangeMultiAttribute_RemoveValue() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - assertEquals("qwe", modificationItems[0].getAttribute().get()); - } - - public void testChangeMultiAttribute_RemoveTwoValues() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - multi.add("rty"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - assertEquals("qwe", modificationItems[0].getAttribute().get(0)); - assertEquals("rty", modificationItems[0].getAttribute().get(1)); - } - - public void testChangeMultiAttribute_RemoveAllValues() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", null); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - } - - public void testChangeMultiAttribute_SameValue() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123", "qwe" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(0, modificationItems.length); - } - - public void testChangeMultiAttribute_AddAndRemoveValue() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - multi.add("rty"); - multi.add("uio"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("abc", new String[] { "123", "qwe", "klytt", - "kalle" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(2, modificationItems.length); - - Attribute modifiedAttribute = modificationItems[0].getAttribute(); - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] - .getModificationOp()); - assertEquals("abc", modifiedAttribute.getID()); - assertEquals(2, modifiedAttribute.size()); - assertEquals("rty", modifiedAttribute.get(0)); - assertEquals("uio", modifiedAttribute.get(1)); - - assertEquals(DirContext.ADD_ATTRIBUTE, modificationItems[1] - .getModificationOp()); - modifiedAttribute = modificationItems[1].getAttribute(); - assertEquals("abc", modifiedAttribute.getID()); - assertEquals(2, modifiedAttribute.size()); - assertEquals("klytt", modifiedAttribute.get(0)); - assertEquals("kalle", modifiedAttribute.get(1)); - } - - public void testAddAttribute_Multivalue() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - Attribute multi = new BasicAttribute("abc"); - multi.add("123"); - multi.add("qwe"); - fixtureAttrs.put(multi); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValues("def", new String[] { "kalle", "klytt" }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(1, modificationItems.length); - assertEquals("def", modificationItems[0].getAttribute().getID()); - } - - public void testChangeAttributeTwice() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - fixtureAttrs.put(new BasicAttribute("abc", "123")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValue("abc", "234"); // change - tested.setAttributeValue("abc", "987"); - // change a second time - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); - Attribute attr = mods[0].getAttribute(); - assertEquals("abc", (String) attr.getID()); - assertEquals("987", (String) attr.get()); - - tested.update(); - mods = tested.getModificationItems(); - assertEquals(0, mods.length); - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - Attributes attrs = tested.getAttributes(); - attr = attrs.get("abc"); - assertEquals("987", (String) attr.get()); - assertEquals("987", tested.getStringAttribute("abc")); - } - - public void testAddReplaceAndChangeAttribute() throws Exception { - final Attributes fixtureAttrs = new BasicAttributes(); - fixtureAttrs.put(new BasicAttribute("abc", "123")); - fixtureAttrs.put(new BasicAttribute("qwe", "42")); - class TestableDirContextAdapter extends DirContextAdapter { - public TestableDirContextAdapter() { - super(fixtureAttrs, null); - setUpdateMode(true); - } - } - tested = new TestableDirContextAdapter(); - assertTrue(tested.isUpdateMode()); - tested.setAttributeValue("abc", "234"); // change - tested.setAttributeValue("qwe", null); // remove - tested.setAttributeValue("zzz", "new"); // new - Attributes attrs = tested.getAttributes(); - Attribute attr = attrs.get("abc"); - assertEquals("123", (String) attr.get()); - assertEquals(2, attrs.size()); - - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(3, mods.length); - String[] modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(3, modNames.length); - - ModificationItem mod = getModificationItem(mods, - DirContext.REPLACE_ATTRIBUTE); - assertNotNull(mod); - attr = mod.getAttribute(); - assertEquals("abc", (String) attr.getID()); - assertEquals("234", (String) attr.get()); - - mod = getModificationItem(mods, DirContext.REMOVE_ATTRIBUTE); - assertNotNull(mod); - attr = mod.getAttribute(); - assertEquals("qwe", (String) attr.getID()); - - mod = getModificationItem(mods, DirContext.ADD_ATTRIBUTE); - assertNotNull(mod); - attr = mod.getAttribute(); - assertEquals("zzz", (String) attr.getID()); - assertEquals("new", (String) attr.get()); - - tested.update(); - mods = tested.getModificationItems(); - assertEquals(0, mods.length); - modNames = tested.getNamesOfModifiedAttributes(); - assertEquals(0, modNames.length); - - attrs = tested.getAttributes(); - assertEquals(2, attrs.size()); - attr = attrs.get("abc"); - assertEquals("234", (String) attr.get()); - assertEquals("new", tested.getStringAttribute("zzz")); - } - - /** - * Test for LDAP-15: DirContextAdapter.setAttribute(). Verifies that setting - * an Attribute should modify updatedAttrs if in update mode. - * - * @throws NamingException - */ - public void testSetAttribute_UpdateMode() throws NamingException { - // Set original attribute value - Attribute attribute = new BasicAttribute("cn", "john doe"); - tested.setAttribute(attribute); - - // Set to update mode - tested.setUpdateMode(true); - - // Perform test - update the attribute - Attribute updatedAttribute = new BasicAttribute("cn", "nisse hult"); - tested.setAttribute(updatedAttribute); - - // Verify result - ModificationItem[] mods = tested.getModificationItems(); - assertEquals(1, mods.length); - assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); - - Attribute modificationAttribute = mods[0].getAttribute(); - assertEquals("cn", modificationAttribute.getID()); - assertEquals("nisse hult", modificationAttribute.get()); - } - - public void testGetStringAttributes_NullValue() { - String result = tested.getStringAttribute("someAbsentAttribute"); - assertNull(result); - } - - public void testGetStringAttributes_AttributeExists_NullValue() { - tested.setAttribute(new BasicAttribute("someAttribute", null)); - String result = tested.getStringAttribute("someAttribute"); - assertNull(result); - } - - private ModificationItem getModificationItem(ModificationItem[] mods, - int operation) { - for (int i = 0; i < mods.length; i++) { - if (mods[i].getModificationOp() == operation) - return mods[i]; - } - return null; - } - - public void testModifyMultiValueAttributeModificationOrder() - throws NamingException { - BasicAttribute attribute = new BasicAttribute("abc"); - attribute.add("Some Person"); - attribute.add("Some Other Person"); - - tested.setAttribute(attribute); - tested.setUpdateMode(true); - - tested.setAttributeValues("abc", new String[] { "some person", - "Some Other Person" }); - - // Perform test - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(2, modificationItems.length); - ModificationItem modificationItem = modificationItems[0]; - assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItem - .getModificationOp()); - assertEquals("Some Person", modificationItem.getAttribute().get()); - modificationItem = modificationItems[1]; - assertEquals(DirContext.ADD_ATTRIBUTE, modificationItem - .getModificationOp()); - assertEquals("some person", modificationItem.getAttribute().get()); - } - - /** - * Test for LDAP-13. - */ - public void testModifyAttributeByteArray() { - tested.setAttribute(new BasicAttribute("abc", new byte[] { 1, 2, 3 })); - - tested.setUpdateMode(true); - - // Perform test - tested.setAttributeValue("abc", new byte[] { 1, 2, 3 }); - - ModificationItem[] modificationItems = tested.getModificationItems(); - assertEquals(0, modificationItems.length); - } - - /** - * Test for LDAP-109, since also DirContextAdapter may get an invalid - * CompositeName sent to it. - */ - public void testConstructorUsingCompositeNameWithBackslashes() - throws Exception { - CompositeName compositeName = new CompositeName(); - compositeName.add("cn=Some\\\\Person6,ou=company1,c=Sweden"); - DirContextAdapter adapter = new DirContextAdapter(compositeName); - assertEquals("cn=Some\\\\Person6,ou=company1,c=Sweden", adapter.getDn() - .toString()); - } - - public void testStringConstructor() { - DirContextAdapter tested = new DirContextAdapter("cn=john doe, ou=company"); - assertEquals(new DistinguishedName("cn=john doe, ou=company"), tested.getDn()); - } -} +/* + * Copyright 2005-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ldap.core; + +import java.util.Iterator; +import java.util.SortedSet; + +import javax.naming.CompositeName; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; +import javax.naming.directory.BasicAttributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; + +import junit.framework.TestCase; + +/** + * Tests the DirContextAdapter class. + * + * @author Andreas Ronge + * @author Mattias Hellborg Arthursson + * @author Ulrik Sandberg + */ +public class DirContextAdapterTest extends TestCase { + private static final DistinguishedName BASE_NAME = new DistinguishedName( + "dc=jayway, dc=se"); + + private static final DistinguishedName DUMMY_NAME = new DistinguishedName( + "c=SE, dc=jayway, dc=se"); + + private DirContextAdapter tested; + + protected void setUp() throws Exception { + super.setUp(); + tested = new DirContextAdapter(); + } + + protected void tearDown() throws Exception { + super.tearDown(); + } + + public void testSetUpdateMode() throws Exception { + assertFalse(tested.isUpdateMode()); + tested.setUpdateMode(true); + assertTrue(tested.isUpdateMode()); + tested.setUpdateMode(false); + assertFalse(tested.isUpdateMode()); + } + + public void testGetModificationItems() throws Exception { + ModificationItem[] items = tested.getModificationItems(); + assertEquals(0, items.length); + tested.setUpdateMode(true); + assertEquals(0, items.length); + } + + public void testAlwaysReplace() throws Exception { + ModificationItem[] items = tested.getModificationItems(); + assertEquals(0, items.length); + tested.setUpdateMode(true); + assertEquals(0, items.length); + } + + public void testGetStringAttributeWhenAttributeDoesNotExist() throws Exception { + String s = tested.getStringAttribute("does not exist"); + assertNull(s); + } + + public void testGetStringAttributeWhenAttributeDoesExistButWithNoValue() throws Exception { + final Attributes attrs = new BasicAttributes(); + attrs.put(new BasicAttribute("abc")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + String s = tested.getStringAttribute("abc"); + assertNull(s); + } + + public void testAttributeExistsWhenAttributeDoesExistButWithNoValue() throws Exception { + final Attributes attrs = new BasicAttributes(); + attrs.put(new BasicAttribute("abc")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + boolean result = tested.attributeExists("abc"); + assertEquals(true, result); + } + + public void testAttributeExistsWhenAttributeDoesNotExist() throws Exception { + boolean result = tested.attributeExists("does not exist"); + assertEquals(false, result); + } + + public void testGetStringAttributeWhenAttributeExists() throws Exception { + final Attributes attrs = new BasicAttributes(); + attrs.put(new BasicAttribute("abc", "def")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + String s = tested.getStringAttribute("abc"); + assertEquals("def", s); + } + + public void testGetStringAttributesWhenMultiValueAttributeExists() throws Exception { + final Attributes attrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("234"); + attrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + String s[] = tested.getStringAttributes("abc"); + assertEquals("123", s[0]); + assertEquals("234", s[1]); + assertEquals(2, s.length); + } + + public void testGetStringAttributesExistsWithInvalidType() throws Exception { + final Attributes attrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add(new Object()); + attrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + try { + tested.getStringAttributes("abc"); + fail("ClassCastException expected"); + } + catch (ArrayStoreException expected) { + assertTrue(true); + } + } + + public void testGetStringAttributesExistsEmpty() throws Exception { + final Attributes attrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + attrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + String s[] = tested.getStringAttributes("abc"); + assertNotNull(s); + assertEquals(0, s.length); + } + + public void testGetStringAttributesNotExists() throws Exception { + String s[] = tested.getStringAttributes("abc"); + assertNull(s); + } + + public void testGetAttributesSortedStringSetExists() throws Exception { + final Attributes attrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("234"); + attrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + SortedSet s = tested.getAttributeSortedStringSet("abc"); + assertNotNull(s); + assertEquals(2, s.size()); + Iterator it = s.iterator(); + assertEquals("123", it.next()); + assertEquals("234", it.next()); + } + + public void testGetAttributesSortedStringSetNotExists() throws Exception { + final Attributes attrs = new BasicAttributes(); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(attrs, null); + } + } + tested = new TestableDirContextAdapter(); + SortedSet s = tested.getAttributeSortedStringSet("abc"); + assertNull(s); + } + + public void testAddAttributeValue() throws NamingException { + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals("123", (String) attr.get()); + } + + public void testAddAttributeValueAttributeWithOtherValueExists() + throws NamingException { + tested.setAttribute(new BasicAttribute("abc", "321")); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals("321", (String) attr.get(0)); + assertEquals("123", (String) attr.get(1)); + } + + public void testAddAttributeValueAttributeWithSameValueExists() + throws NamingException { + tested.setAttribute(new BasicAttribute("abc", "123")); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals(1, attr.size()); + assertEquals("123", (String) attr.get(0)); + } + + public void testAddAttributeValueInUpdateMode() throws NamingException { + tested.setUpdateMode(true); + tested.addAttributeValue("abc", "123"); + + // Perform test + Attributes attrs = tested.getAttributes(); + assertNull(attrs.get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute attribute = modificationItems[0].getAttribute(); + assertEquals("abc", attribute.getID()); + assertEquals("123", attribute.get()); + } + + public void testAddAttributeValueInUpdateModeAttributeWhenOtherValueExistsInOrigAttrs() + throws NamingException { + + tested.setAttribute(new BasicAttribute("abc", "321")); + tested.setUpdateMode(true); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + assertNotNull(attrs.get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute attribute = modificationItems[0].getAttribute(); + assertEquals(1, attribute.size()); + assertEquals("abc", attribute.getID()); + assertEquals("123", attribute.get()); + } + + public void testGetModificationItemsOnAddAttributeValueInUpdateModeAttributeWhenSameValueExistsInOrigAttrs() + throws NamingException { + + tested.setAttribute(new BasicAttribute("abc", "123")); + tested.setUpdateMode(true); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + assertNotNull(attrs.get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(0, modificationItems.length); + } + + public void testAddAttributeValueInUpdateModeAttributeWithOtherValueExistsInUpdAttrs() + throws NamingException { + tested.setUpdateMode(true); + tested.setAttributeValue("abc", "321"); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + assertNull(attrs.get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute attribute = modificationItems[0].getAttribute(); + assertEquals("abc", attribute.getID()); + assertEquals("321", attribute.get(0)); + assertEquals("123", attribute.get(1)); + } + + public void testAddAttributeValueInUpdateModeAttributeWithSameValueExistsInUpdAttrs() + throws NamingException { + tested.setUpdateMode(true); + tested.setAttributeValue("abc", "123"); + + // Perform test + tested.addAttributeValue("abc", "123"); + + Attributes attrs = tested.getAttributes(); + assertNull(attrs.get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute attribute = modificationItems[0].getAttribute(); + assertEquals(1, attribute.size()); + assertEquals("abc", attribute.getID()); + assertEquals("123", attribute.get()); + } + + public void testRemoveAttributeValueAttributeDoesntExist() { + // Perform test + tested.removeAttributeValue("abc", "123"); + + Attributes attributes = tested.getAttributes(); + assertNull(attributes.get("abc")); + } + + public void testRemoveAttributeValueAttributeWithOtherValueExists() + throws NamingException { + tested.setAttribute(new BasicAttribute("abc", "321")); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + Attributes attributes = tested.getAttributes(); + Attribute attr = attributes.get("abc"); + assertNotNull(attr); + assertEquals(1, attr.size()); + assertEquals("321", attr.get()); + } + + public void testRemoveAttributeValueAttributeWithSameValueExists() { + tested.setAttribute(new BasicAttribute("abc", "123")); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + Attributes attributes = tested.getAttributes(); + Attribute attr = attributes.get("abc"); + assertNull(attr); + } + + public void testRemoveAttributeValueAttributeWithOtherAndSameValueExists() + throws NamingException { + BasicAttribute basicAttribute = new BasicAttribute("abc"); + basicAttribute.add("123"); + basicAttribute.add("321"); + tested.setAttribute(basicAttribute); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + Attributes attributes = tested.getAttributes(); + Attribute attr = attributes.get("abc"); + assertNotNull(attr); + assertEquals(1, attr.size()); + assertEquals("321", attr.get()); + } + + public void testRemoveAttributeValueInUpdateMode() { + tested.setUpdateMode(true); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + assertNull(tested.getAttributes().get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(0, modificationItems.length); + } + + public void testRemoveAttributeValueInUpdateModeSameValueExistsInUpdatedAttrs() { + tested.setUpdateMode(true); + tested.setAttributeValue("abc", "123"); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + assertNull(tested.getAttributes().get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(0, modificationItems.length); + } + + public void testRemoveAttributeValueInUpdateModeOtherValueExistsInUpdatedAttrs() + throws NamingException { + tested.setUpdateMode(true); + tested.setAttributeValue("abc", "321"); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + assertNull(tested.getAttributes().get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute modificationAttribute = modificationItems[0].getAttribute(); + assertEquals("abc", modificationAttribute.getID()); + assertEquals(1, modificationAttribute.size()); + assertEquals("321", modificationAttribute.get()); + } + + public void testRemoveAttributeValueInUpdateModeOtherAndSameValueExistsInUpdatedAttrs() + throws NamingException { + tested.setUpdateMode(true); + tested.setAttributeValues("abc", new String[] { "321", "123" }); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + assertNull(tested.getAttributes().get("abc")); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute modificationAttribute = modificationItems[0].getAttribute(); + assertEquals("abc", modificationAttribute.getID()); + assertEquals(1, modificationAttribute.size()); + } + + public void testRemoveAttributeValueInUpdateModeSameValueExistsInOrigAttrs() { + tested.setAttribute(new BasicAttribute("abc", "123")); + tested.setUpdateMode(true); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute modificationAttribute = modificationItems[0].getAttribute(); + assertEquals("abc", modificationAttribute.getID()); + assertEquals(0, modificationAttribute.size()); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + } + + public void testRemoveAttributeValueInUpdateModeSameAndOtherValueExistsInOrigAttrs() + throws NamingException { + BasicAttribute basicAttribute = new BasicAttribute("abc"); + basicAttribute.add("123"); + basicAttribute.add("321"); + tested.setAttribute(basicAttribute); + tested.setUpdateMode(true); + + // Perform test + tested.removeAttributeValue("abc", "123"); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + Attribute modificationAttribute = modificationItems[0].getAttribute(); + assertEquals("abc", modificationAttribute.getID()); + assertEquals(1, modificationAttribute.size()); + assertEquals("123", modificationAttribute.get()); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + } + + public void testSetStringAttribute() throws Exception { + assertFalse(tested.isUpdateMode()); + tested.setAttributeValue("abc", "123"); + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals("123", (String) attr.get()); + } + + public void testSetStringAttributeNull() throws Exception { + assertFalse(tested.isUpdateMode()); + tested.setAttributeValue("abc", null); + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertNull(attr); + } + + public void testAddAttribute() throws Exception { + tested.setUpdateMode(true); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValue("abc", "123"); + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertNull(attr); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.ADD_ATTRIBUTE, mods[0].getModificationOp()); + attr = mods[0].getAttribute(); + assertEquals("123", (String) attr.get()); + + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(1, modNames.length); + assertEquals("abc", modNames[0]); + + tested.update(); + mods = tested.getModificationItems(); + assertEquals(0, mods.length); + modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + attrs = tested.getAttributes(); + attr = attrs.get("abc"); + assertEquals("123", (String) attr.get()); + } + + public void testGetDn() throws Exception { + DirContextAdapter tested = new DirContextAdapter(DUMMY_NAME); + Name result = tested.getDn(); + assertEquals(DUMMY_NAME, result); + } + + public void testGetDn_BasePath() { + DirContextAdapter tested = new DirContextAdapter(null, DUMMY_NAME, + BASE_NAME); + Name result = tested.getDn(); + assertEquals(DUMMY_NAME, result); + } + + public void testGetNameInNamespace() { + DirContextAdapter tested = new DirContextAdapter(DUMMY_NAME); + String result = tested.getNameInNamespace(); + assertEquals(DUMMY_NAME.toString(), result); + } + + public void testGetNameInNamespace_BasePath() { + DirContextAdapter tested = new DirContextAdapter(null, + new DistinguishedName("c=SE"), BASE_NAME); + String result = tested.getNameInNamespace(); + assertEquals(DUMMY_NAME.toString(), result); + } + + public void testAddMultiAttributes() throws Exception { + tested.setUpdateMode(true); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123", "456" }); + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertNull(attr); + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.ADD_ATTRIBUTE, mods[0].getModificationOp()); + attr = mods[0].getAttribute(); + assertEquals(2, attr.size()); + assertEquals("123", (String) attr.get(0)); + assertEquals("456", (String) attr.get(1)); + + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(1, modNames.length); + assertEquals("abc", modNames[0]); + + tested.update(); + mods = tested.getModificationItems(); + assertEquals(0, mods.length); + modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + attrs = tested.getAttributes(); + attr = attrs.get("abc"); + assertEquals("123", (String) attr.get(0)); + assertEquals("456", (String) attr.get(1)); + } + + public void testRemoveAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + fixtureAttrs.put(new BasicAttribute("abc", "123")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + + tested.setUpdateMode(true); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValue("abc", null); + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals("123", (String) attr.get()); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REMOVE_ATTRIBUTE, mods[0].getModificationOp()); + attr = mods[0].getAttribute(); + assertEquals("abc", (String) attr.getID()); + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(1, modNames.length); + assertEquals("abc", modNames[0]); + + tested.update(); + mods = tested.getModificationItems(); + assertEquals(0, mods.length); + modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + attrs = tested.getAttributes(); + attr = attrs.get("abc"); + assertNull(attr); + } + + public void testRemoveMultiAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute abc = new BasicAttribute("abc"); + abc.add("123"); + abc.add("456"); + fixtureAttrs.put(abc); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + + tested.setUpdateMode(true); + tested.setAttributeValues("abc", new String[] {}); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REMOVE_ATTRIBUTE, mods[0].getModificationOp()); + Attribute attr = mods[0].getAttribute(); + assertEquals("abc", (String) attr.getID()); + assertEquals(0, attr.size()); + } + + public void testChangeAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + fixtureAttrs.put(new BasicAttribute("abc", "123")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + tested.setAttributeValue("abc", "234"); // change + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); + Attribute attr = mods[0].getAttribute(); + assertEquals("abc", (String) attr.getID()); + assertEquals("234", (String) attr.get()); + } + + public void testNoChangeAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + fixtureAttrs.put(new BasicAttribute("abc", "123")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValue("abc", "123"); // change + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(0, mods.length); + } + + public void testNoChangeMultiAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123", "qwe" }); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(0, mods.length); + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + } + + public void testNoChangeMultiAttributeOrderDoesNotMatter() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + tested.setAttributeValues("abc", new String[] { "qwe", "123" }); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(0, mods.length); + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + } + + public void testChangeMultiAttributeOrderDoesMatter() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "qwe", "123" }, true); + + // change + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); + Attribute attr = mods[0].getAttribute(); + assertEquals("qwe", attr.get(0)); + assertEquals("123", attr.get(1)); + } + + /** + * Test case corresponding to LDAP-96 in Spring Jira. + * http://jira.springframework.org/browse/LDAP-96 + */ + public void testChangeMultiAttributeOrderDoesMatterLDAP96() + throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("title"); + multi.add("Juergen"); + multi.add("George"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("title", new String[] { "Jim", "George", + "Juergen" }, true); + + // change + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); + Attribute attr = mods[0].getAttribute(); + assertEquals("Jim", attr.get(0)); + assertEquals("George", attr.get(1)); + assertEquals("Juergen", attr.get(2)); + } + + public void testChangeMultiAttribute_AddValue() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested + .setAttributeValues("abc", + new String[] { "123", "qwe", "klytt" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + assertEquals(DirContext.ADD_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + assertEquals("klytt", modificationItems[0].getAttribute().get()); + } + + public void testChangeMultiAttribute_RemoveValue() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + assertEquals("qwe", modificationItems[0].getAttribute().get()); + } + + public void testChangeMultiAttribute_RemoveTwoValues() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + multi.add("rty"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + assertEquals("qwe", modificationItems[0].getAttribute().get(0)); + assertEquals("rty", modificationItems[0].getAttribute().get(1)); + } + + public void testChangeMultiAttribute_RemoveAllValues() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", null); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + } + + public void testChangeMultiAttribute_SameValue() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123", "qwe" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(0, modificationItems.length); + } + + public void testChangeMultiAttribute_AddAndRemoveValue() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + multi.add("rty"); + multi.add("uio"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("abc", new String[] { "123", "qwe", "klytt", + "kalle" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(2, modificationItems.length); + + Attribute modifiedAttribute = modificationItems[0].getAttribute(); + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItems[0] + .getModificationOp()); + assertEquals("abc", modifiedAttribute.getID()); + assertEquals(2, modifiedAttribute.size()); + assertEquals("rty", modifiedAttribute.get(0)); + assertEquals("uio", modifiedAttribute.get(1)); + + assertEquals(DirContext.ADD_ATTRIBUTE, modificationItems[1] + .getModificationOp()); + modifiedAttribute = modificationItems[1].getAttribute(); + assertEquals("abc", modifiedAttribute.getID()); + assertEquals(2, modifiedAttribute.size()); + assertEquals("klytt", modifiedAttribute.get(0)); + assertEquals("kalle", modifiedAttribute.get(1)); + } + + public void testAddAttribute_Multivalue() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + Attribute multi = new BasicAttribute("abc"); + multi.add("123"); + multi.add("qwe"); + fixtureAttrs.put(multi); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValues("def", new String[] { "kalle", "klytt" }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(1, modificationItems.length); + assertEquals("def", modificationItems[0].getAttribute().getID()); + } + + public void testChangeAttributeTwice() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + fixtureAttrs.put(new BasicAttribute("abc", "123")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValue("abc", "234"); // change + tested.setAttributeValue("abc", "987"); + // change a second time + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); + Attribute attr = mods[0].getAttribute(); + assertEquals("abc", (String) attr.getID()); + assertEquals("987", (String) attr.get()); + + tested.update(); + mods = tested.getModificationItems(); + assertEquals(0, mods.length); + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + Attributes attrs = tested.getAttributes(); + attr = attrs.get("abc"); + assertEquals("987", (String) attr.get()); + assertEquals("987", tested.getStringAttribute("abc")); + } + + public void testAddReplaceAndChangeAttribute() throws Exception { + final Attributes fixtureAttrs = new BasicAttributes(); + fixtureAttrs.put(new BasicAttribute("abc", "123")); + fixtureAttrs.put(new BasicAttribute("qwe", "42")); + class TestableDirContextAdapter extends DirContextAdapter { + public TestableDirContextAdapter() { + super(fixtureAttrs, null); + setUpdateMode(true); + } + } + tested = new TestableDirContextAdapter(); + assertTrue(tested.isUpdateMode()); + tested.setAttributeValue("abc", "234"); // change + tested.setAttributeValue("qwe", null); // remove + tested.setAttributeValue("zzz", "new"); // new + Attributes attrs = tested.getAttributes(); + Attribute attr = attrs.get("abc"); + assertEquals("123", (String) attr.get()); + assertEquals(2, attrs.size()); + + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(3, mods.length); + String[] modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(3, modNames.length); + + ModificationItem mod = getModificationItem(mods, + DirContext.REPLACE_ATTRIBUTE); + assertNotNull(mod); + attr = mod.getAttribute(); + assertEquals("abc", (String) attr.getID()); + assertEquals("234", (String) attr.get()); + + mod = getModificationItem(mods, DirContext.REMOVE_ATTRIBUTE); + assertNotNull(mod); + attr = mod.getAttribute(); + assertEquals("qwe", (String) attr.getID()); + + mod = getModificationItem(mods, DirContext.ADD_ATTRIBUTE); + assertNotNull(mod); + attr = mod.getAttribute(); + assertEquals("zzz", (String) attr.getID()); + assertEquals("new", (String) attr.get()); + + tested.update(); + mods = tested.getModificationItems(); + assertEquals(0, mods.length); + modNames = tested.getNamesOfModifiedAttributes(); + assertEquals(0, modNames.length); + + attrs = tested.getAttributes(); + assertEquals(2, attrs.size()); + attr = attrs.get("abc"); + assertEquals("234", (String) attr.get()); + assertEquals("new", tested.getStringAttribute("zzz")); + } + + /** + * Test for LDAP-15: DirContextAdapter.setAttribute(). Verifies that setting + * an Attribute should modify updatedAttrs if in update mode. + * + * @throws NamingException + */ + public void testSetAttribute_UpdateMode() throws NamingException { + // Set original attribute value + Attribute attribute = new BasicAttribute("cn", "john doe"); + tested.setAttribute(attribute); + + // Set to update mode + tested.setUpdateMode(true); + + // Perform test - update the attribute + Attribute updatedAttribute = new BasicAttribute("cn", "nisse hult"); + tested.setAttribute(updatedAttribute); + + // Verify result + ModificationItem[] mods = tested.getModificationItems(); + assertEquals(1, mods.length); + assertEquals(DirContext.REPLACE_ATTRIBUTE, mods[0].getModificationOp()); + + Attribute modificationAttribute = mods[0].getAttribute(); + assertEquals("cn", modificationAttribute.getID()); + assertEquals("nisse hult", modificationAttribute.get()); + } + + public void testGetStringAttributes_NullValue() { + String result = tested.getStringAttribute("someAbsentAttribute"); + assertNull(result); + } + + public void testGetStringAttributes_AttributeExists_NullValue() { + tested.setAttribute(new BasicAttribute("someAttribute", null)); + String result = tested.getStringAttribute("someAttribute"); + assertNull(result); + } + + private ModificationItem getModificationItem(ModificationItem[] mods, + int operation) { + for (int i = 0; i < mods.length; i++) { + if (mods[i].getModificationOp() == operation) + return mods[i]; + } + return null; + } + + public void testModifyMultiValueAttributeModificationOrder() + throws NamingException { + BasicAttribute attribute = new BasicAttribute("abc"); + attribute.add("Some Person"); + attribute.add("Some Other Person"); + + tested.setAttribute(attribute); + tested.setUpdateMode(true); + + tested.setAttributeValues("abc", new String[] { "some person", + "Some Other Person" }); + + // Perform test + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(2, modificationItems.length); + ModificationItem modificationItem = modificationItems[0]; + assertEquals(DirContext.REMOVE_ATTRIBUTE, modificationItem + .getModificationOp()); + assertEquals("Some Person", modificationItem.getAttribute().get()); + modificationItem = modificationItems[1]; + assertEquals(DirContext.ADD_ATTRIBUTE, modificationItem + .getModificationOp()); + assertEquals("some person", modificationItem.getAttribute().get()); + } + + /** + * Test for LDAP-13. + */ + public void testModifyAttributeByteArray() { + tested.setAttribute(new BasicAttribute("abc", new byte[] { 1, 2, 3 })); + + tested.setUpdateMode(true); + + // Perform test + tested.setAttributeValue("abc", new byte[] { 1, 2, 3 }); + + ModificationItem[] modificationItems = tested.getModificationItems(); + assertEquals(0, modificationItems.length); + } + + /** + * Test for LDAP-109, since also DirContextAdapter may get an invalid + * CompositeName sent to it. + */ + public void testConstructorUsingCompositeNameWithBackslashes() + throws Exception { + CompositeName compositeName = new CompositeName(); + compositeName.add("cn=Some\\\\Person6,ou=company1,c=Sweden"); + DirContextAdapter adapter = new DirContextAdapter(compositeName); + assertEquals("cn=Some\\\\Person6,ou=company1,c=Sweden", adapter.getDn() + .toString()); + } + + public void testStringConstructor() { + DirContextAdapter tested = new DirContextAdapter("cn=john doe, ou=company"); + assertEquals(new DistinguishedName("cn=john doe, ou=company"), tested.getDn()); + } +}