/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://IdentityConnectors.dev.java.net/legal/license.txt * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at identityconnectors/legal/license.txt. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.ldap; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; /** * An implementation of {@link Attributes} which delegates to a given * {@code Attributes} instance while adding some * attributes to the list if already not present, or replacing the existing * values if such attributes are present. */ public abstract class AppendingAttributes implements Attributes { private static final long serialVersionUID = 1L; protected final Attributes delegate; public AppendingAttributes(Attributes delegate) { this.delegate = delegate; } protected abstract Set<String> getAttributeIDsToAppend(); protected abstract Attribute getAttributeToAppend(String attrID); public abstract Object clone(); public final Attribute get(String attrID) { String attrIDToAppend = getNormalizedAttributeIDToAppend(attrID); if (attrIDToAppend != null) { return getAttributeToAppend(attrIDToAppend); } else { return delegate.get(attrID); } } private String getNormalizedAttributeIDToAppend(String attrID) { if (delegate.isCaseIgnored()) { for (String attributeIDToAppend : getAttributeIDsToAppend()) { if (attributeIDToAppend.equalsIgnoreCase(attrID)) { return attributeIDToAppend; } } } else { if (getAttributeIDsToAppend().contains(attrID)) { return attrID; } } return null; } public final NamingEnumeration<? extends Attribute> getAll() { return new AttributeAppendingEnumeration(delegate.getAll()); } public final NamingEnumeration<String> getIDs() { return new AttributeIDAppendingEnumeration(delegate.getIDs()); } public final boolean isCaseIgnored() { return delegate.isCaseIgnored(); } public final Attribute put(Attribute attr) { throw new UnsupportedOperationException(); } public final Attribute put(String attrID, Object val) { throw new UnsupportedOperationException(); } public final Attribute remove(String attrID) { throw new UnsupportedOperationException(); } public final int size() { int size = delegate.size(); for (String attributeIDToAppend : getAttributeIDsToAppend()) { if (delegate.get(attributeIDToAppend) == null) { size++; } } return size; } private abstract class AppendingEnumeration<T> implements NamingEnumeration<T> { private final NamingEnumeration<? extends T> delegate; private Enumeration<T> remainingValues; public AppendingEnumeration(NamingEnumeration<? extends T> delegate) { this.delegate = delegate; } protected abstract T getReplacementValue(T value); protected abstract Enumeration<T> getRemainingValues(); public void close() throws NamingException { delegate.close(); } public boolean hasMore() throws NamingException { return delegate.hasMore() || hasMoreRemainingValues(); } public T next() throws NamingException { if (delegate.hasMore()) { T next = delegate.next(); // Watch out for null values in the enumeration. if (next != null) { T replacement = getReplacementValue(next); if (replacement != null) { next = replacement; } } return next; } else if (hasMoreRemainingValues()) { return getNextRemainingValue(); } else { return delegate.next(); // Throws NoSuchElementException. } } public boolean hasMoreElements() { return delegate.hasMoreElements() || hasMoreRemainingValues(); } public T nextElement() { if (delegate.hasMoreElements()) { T next = delegate.nextElement(); // Watch out for null values in the enumeration. if (next != null) { T replacement = getReplacementValue(next); if (replacement != null) { next = replacement; } } return next; } else if (hasMoreRemainingValues()) { return getNextRemainingValue(); } else { return delegate.nextElement(); // Throws NoSuchElementException. } } private boolean hasMoreRemainingValues() { if (remainingValues == null) { remainingValues = getRemainingValues(); } return remainingValues.hasMoreElements(); } private T getNextRemainingValue() { assert remainingValues != null; return remainingValues.nextElement(); } } private final class AttributeAppendingEnumeration extends AppendingEnumeration<Attribute> { private Set<String> replaced = new HashSet<String>(); public AttributeAppendingEnumeration(NamingEnumeration<? extends Attribute> delegate) { super(delegate); } @Override protected Attribute getReplacementValue(Attribute value) { String attrID = value.getID(); if (getAttributeIDsToAppend().contains(attrID)) { replaced.add(attrID); return getAttributeToAppend(attrID); } else { return null; } } @Override protected Enumeration<Attribute> getRemainingValues() { final Set<String> remaining = getAttributeIDsToAppend(); remaining.removeAll(replaced); return new Enumeration<Attribute>() { private final Iterator<String> iterator = remaining.iterator(); public boolean hasMoreElements() { return iterator.hasNext(); } public Attribute nextElement() { return getAttributeToAppend(iterator.next()); } }; } } private final class AttributeIDAppendingEnumeration extends AppendingEnumeration<String> { private Set<String> replaced = new HashSet<String>(); public AttributeIDAppendingEnumeration(NamingEnumeration<String> delegate) { super(delegate); } @Override protected String getReplacementValue(String value) { if (getAttributeIDsToAppend().contains(value)) { replaced.add(value); return value; } else { return null; } } @Override protected Enumeration<String> getRemainingValues() { final Set<String> remaining = getAttributeIDsToAppend(); remaining.removeAll(replaced); return new Enumeration<String>() { private final Iterator<String> iterator = remaining.iterator(); public boolean hasMoreElements() { return iterator.hasNext(); } public String nextElement() { return iterator.next(); } }; } } }