/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.admin.client.ldap; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.naming.NameNotFoundException; 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.ldap.LdapName; import org.opends.server.TestCaseUtils; import org.opends.server.types.AttributeValue; import org.opends.server.types.DN; import org.opends.server.types.DirectoryException; import org.opends.server.types.Entry; import org.opends.server.types.RDN; import org.testng.Assert; /** * A mock LDAP connection which fakes up search results based on some * LDIF content. Implementations should override the modify operations * in order to get provide the correct fake behavior. */ public class MockLDAPConnection extends LDAPConnection { /** * A mock entry. */ private static final class MockEntry { // The entry's attributes. private final Attributes attributes; // The entry's children. private final List<MockEntry> children; // The name of this mock entry. private final DN dn; /** * Create a new mock entry with the provided name and attributes. * * @param dn * The name of the entry. * @param attributes * The attributes. */ public MockEntry(DN dn, Attributes attributes) { this.dn = dn; this.attributes = attributes; this.children = new LinkedList<MockEntry>(); } /** * Get the entry's attributes. * * @return Returns the entry's attributes. */ public Attributes getAttributes() { return attributes; } /** * Get the entry's children. * * @return Returns the entry's children. */ public List<MockEntry> getChildren() { return children; } /** * Get the entry's name. * * @return Returns the entry's name. */ public DN getDN() { return dn; } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("dn="); builder.append(dn); builder.append(" attributes="); builder.append(attributes); return builder.toString(); } } // All the entries. private final Map<DN, MockEntry> entries; // The single root entry. private final MockEntry rootEntry; /** * Creates a new mock LDAP connection. */ public MockLDAPConnection() { this.rootEntry = new MockEntry(DN.nullDN(), new BasicAttributes()); this.entries = new HashMap<DN, MockEntry>(); this.entries.put(DN.nullDN(), this.rootEntry); } /** * {@inheritDoc} */ public void createEntry(LdapName dn, Attributes attributes) throws NamingException { throw new UnsupportedOperationException("createEntry"); } /** * {@inheritDoc} */ public void deleteSubtree(LdapName dn) throws NamingException { throw new UnsupportedOperationException("deleteSubtree"); } /** * {@inheritDoc} */ @Override public boolean entryExists(LdapName dn) throws NamingException { return getEntry(dn) != null; } /** * Imports the provided LDIF into this mock connection. * * @param lines * The LDIF. */ public final void importLDIF(String... lines) { try { for (Entry entry : TestCaseUtils.makeEntries(lines)) { addEntry(entry); } } catch (Exception e) { throw new RuntimeException(e); } } /** * {@inheritDoc} */ @Override public Collection<LdapName> listEntries(LdapName dn, String filter) throws NamingException { MockEntry entry = getEntry(dn); if (entry == null) { throw new NameNotFoundException("could not find entry " + dn); } else { LinkedList<LdapName> names = new LinkedList<LdapName>(); for (MockEntry child : entry.children) { names.add(new LdapName(child.getDN().toString())); } return names; } } /** * {@inheritDoc} */ public void modifyEntry(LdapName dn, Attributes mods) throws NamingException { throw new UnsupportedOperationException("modifyEntry"); } /** * {@inheritDoc} */ @Override public Attributes readEntry(LdapName dn, Collection<String> attrIds) throws NamingException { MockEntry entry = getEntry(dn); if (entry == null) { throw new NameNotFoundException("could not find entry " + dn); } else if (attrIds.isEmpty()) { return entry.getAttributes(); } else { Attributes attributes = entry.getAttributes(); Attributes filteredAttributes = new BasicAttributes(); for (String attrId : attrIds) { if (attributes.get(attrId) != null) { filteredAttributes.put(attributes.get(attrId)); } } return filteredAttributes; } } /** * Asserts whether the provided attribute contains exactly the set * of values contained in the provided collection. * * @param attr * The attribute. * @param values * The expected values. * @throws NamingException * If an unexpected problem occurred. */ protected final void assertAttributeEquals(Attribute attr, Collection<String> values) throws NamingException { LinkedList<String> actualValues = new LinkedList<String>(); NamingEnumeration<?> ne = attr.getAll(); while (ne.hasMore()) { actualValues.add(ne.next().toString()); } if (actualValues.size() != values.size() || !actualValues.containsAll(values)) { Assert.fail("Attribute " + attr.getID() + " contains " + actualValues + " but expected " + values); } } /** * Create a new mock entry. * * @param entry * The entry to be added. */ private void addEntry(Entry entry) { MockEntry parent = rootEntry; DN entryDN = entry.getDN(); // Create required glue entries. for (int i = 0; i < entryDN.getNumComponents() - 1; i++) { RDN rdn = entryDN.getRDN(entryDN.getNumComponents() - i - 1); DN dn = parent.getDN().concat(rdn); if (!entries.containsKey(dn)) { MockEntry glue = new MockEntry(dn, new BasicAttributes()); parent.getChildren().add(glue); entries.put(dn, glue); } parent = entries.get(dn); } // We now have the parent entry - so construct the new entry. Attributes attributes = new BasicAttributes(); for (org.opends.server.types.Attribute attribute : entry.getAttributes()) { BasicAttribute ba = new BasicAttribute(attribute.getName()); for (AttributeValue value : attribute) { ba.add(value.getValue().toString()); } attributes.put(ba); } // Add object classes. BasicAttribute oc = new BasicAttribute("objectclass"); for (String s : entry.getObjectClasses().values()) { oc.add(s); } attributes.put(oc); MockEntry child = new MockEntry(entryDN, attributes); parent.getChildren().add(child); entries.put(entryDN, child); } /** * Gets the named entry. * * @param dn * The name of the entry. * @return Returns the mock entry or <code>null</code> if it does * not exist. */ private MockEntry getEntry(LdapName dn) { DN name; try { name = DN.decode(dn.toString()); } catch (DirectoryException e) { throw new RuntimeException(e); } return entries.get(name); } /** * {@inheritDoc} */ @Override public void unbind() { // nothing to do } }