All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.ldap.core.NameAwareAttribute Maven / Gradle / Ivy

There is a newer version: 3.2.4
Show newest version
/*
 * Copyright 2005-2013 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 org.springframework.ldap.InvalidNameException;
import org.springframework.ldap.support.LdapUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.DirContext;
import javax.naming.ldap.LdapName;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * Used internally to make DirContextAdapter properly handle Names as values.
 *
 * @author Mattias Hellborg Arthursson
 * @since 2.0
 */
public final class NameAwareAttribute implements Attribute, Iterable {

    private final String id;
    private final boolean orderMatters;
    private final Set values = new LinkedHashSet();
    private Map valuesAsNames = new HashMap();

    /**
     * Construct a new instance with the specified id and one value.
     * @param id the attribute id
     * @param value the value to start off with
     */
    public NameAwareAttribute(String id, Object value) {
        this(id);
        values.add(value);
    }

    /**
     * Construct a new instance from the supplied Attribute.
     *
     * @param attribute the Attribute to copy.
     */
    public NameAwareAttribute(Attribute attribute) {
        this(attribute.getID(), attribute.isOrdered());
        try {
            NamingEnumeration incomingValues = attribute.getAll();
            while(incomingValues.hasMore()) {
                this.add(incomingValues.next());
            }
        } catch (NamingException e) {
            throw LdapUtils.convertLdapException(e);
        }

        if (attribute instanceof NameAwareAttribute) {
            NameAwareAttribute nameAwareAttribute = (NameAwareAttribute) attribute;
            populateValuesAsNames(nameAwareAttribute, this);
        }
    }

    /**
     * Construct a new instance with the specified id and no values.
     * @param id the attribute id
     */
    public NameAwareAttribute(String id) {
        this(id, false);
    }

    /**
     * Construct a new instance with the specified id, no values and order significance as specified.
     * @param id the attribute id
     * @param orderMatters whether order has significance in this attribute.
     */
    public NameAwareAttribute(String id, boolean orderMatters) {
        this.id = id;
        this.orderMatters = orderMatters;
    }

    @Override
    public NamingEnumeration getAll() {
        return new IterableNamingEnumeration(values);
    }

    @Override
    public Object get() {
        if(values.isEmpty()) {
            return null;
        }

        return values.iterator().next();
    }

    @Override
    public int size() {
        return values.size();
    }

    @Override
    public String getID() {
        return id;
    }

    @Override
    public boolean contains(Object attrVal) {
        return values.contains(attrVal);
    }

    @Override
    public boolean add(Object attrVal) {
        if (attrVal instanceof Name) {
            initValuesAsNames();

            Name name = LdapUtils.newLdapName((Name) attrVal);
            String currentValue = valuesAsNames.get(name);
            String nameAsString = name.toString();
            if(currentValue == null) {
                valuesAsNames.put(name, name.toString());
                values.add(nameAsString);
                return true;
            } else {
                if(!currentValue.equals(nameAsString)) {
                    values.remove(currentValue);
                    values.add(nameAsString);
                }

                return false;
            }
        }

        return values.add(attrVal);
    }

    public void initValuesAsNames() {
        if(hasValuesAsNames()) {
            return;
        }

        Map newValuesAsNames = new HashMap();
        for (Object value : values) {
            if (value instanceof String) {
                String s = (String) value;
                try {
                    newValuesAsNames.put(LdapUtils.newLdapName(s), s);
                } catch (InvalidNameException e) {
                    throw new IllegalArgumentException("This instance has values that are not valid distinguished names; " +
                            "cannot handle Name values", e);
                }
            } else if (value instanceof LdapName) {
                newValuesAsNames.put((LdapName) value, value.toString());
            } else {
                throw new IllegalArgumentException("This instance has non-string attribute values; " +
                        "cannot handle Name values");
            }
        }

        this.valuesAsNames = newValuesAsNames;
    }

    public boolean hasValuesAsNames() {
        return !valuesAsNames.isEmpty();
    }

    @Override
    public boolean remove(Object attrval) {
        if (attrval instanceof Name) {
            initValuesAsNames();

            Name name = LdapUtils.newLdapName((Name) attrval);
            String removedValue = valuesAsNames.remove(name);
            if(removedValue != null) {
                values.remove(removedValue);

                return true;
            }

            return false;
        }
        return values.remove(attrval);
    }

    @Override
    public void clear() {
        values.clear();
    }

    @Override
    public DirContext getAttributeSyntaxDefinition() throws NamingException {
        throw new UnsupportedOperationException();
    }

    @Override
    public DirContext getAttributeDefinition() throws NamingException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isOrdered() {
        return orderMatters;
    }

    /**
     * 

* Due to performance reasons it is not advised to iterate over the attribute's values using this method. * Please use the {@link #iterator()} instead. *

* {@inheritDoc} */ @Override public Object get(int ix) throws NamingException { Iterator iterator = values.iterator(); try { Object value = iterator.next(); for(int i = 0; i < ix; i++) { value = iterator.next(); } return value; } catch (NoSuchElementException e) { throw new IndexOutOfBoundsException("No value at index i"); } } @Override public Object remove(int ix) { Iterator iterator = values.iterator(); try { Object value = iterator.next(); for(int i = 0; i < ix; i++) { value = iterator.next(); } iterator.remove(); if (value instanceof String) { try { valuesAsNames.remove(new LdapName((String) value)); } catch (javax.naming.InvalidNameException ignored) { } } return value; } catch (NoSuchElementException e) { throw new IndexOutOfBoundsException("No value at index i"); } } @Override public void add(int ix, Object attrVal) { throw new UnsupportedOperationException(); } @Override public Object set(int ix, Object attrVal) { throw new UnsupportedOperationException(); } @Override public Object clone() { return new NameAwareAttribute(this); } private void populateValuesAsNames(NameAwareAttribute from, NameAwareAttribute to) { Set> entries = from.valuesAsNames.entrySet(); for (Map.Entry entry : entries) { to.valuesAsNames.put(LdapUtils.newLdapName(entry.getKey()), entry.getValue()); } } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; NameAwareAttribute that = (NameAwareAttribute) o; if (id != null ? !id.equals(that.id) : that.id != null) return false; if(this.values.size() != that.values.size()) { return false; } if(this.orderMatters != that.orderMatters || this.size() != that.size()) { return false; } if(this.hasValuesAsNames() != that.hasValuesAsNames()) { return false; } Set myValues = this.values; Set theirValues = that.values; if(this.hasValuesAsNames()) { // We have Name values - compare these to get // syntactically correct comparison of the values myValues = this.valuesAsNames.keySet(); theirValues = that.valuesAsNames.keySet(); } if(orderMatters) { Iterator thisIterator = myValues.iterator(); Iterator thatIterator = theirValues.iterator(); while(thisIterator.hasNext()) { if(!ObjectUtils.nullSafeEquals(thisIterator.next(), thatIterator.next())) { return false; } } return true; } else { for (Object value : myValues) { if(!CollectionUtils.contains(theirValues.iterator(), value)) { return false; } } return true; } } @Override public int hashCode() { int result = id != null ? id.hashCode() : 0; int valuesHash = 7; Set myValues = this.values; if(hasValuesAsNames()) { myValues = valuesAsNames.keySet(); } for (Object value : myValues) { result += ObjectUtils.nullSafeHashCode(value); } result = 31 * result + valuesHash; return result; } @Override public String toString() { return String.format("NameAwareAttribute; id: %s; hasValuesAsNames: %s; orderMatters: %s; values: %s", id, hasValuesAsNames(), orderMatters, values); } @Override public Iterator iterator() { return values.iterator(); } }