opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -30,12 +30,10 @@ import org.opends.messages.Message; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import org.opends.server.api.ClientConnection; import org.opends.server.api.plugin.PluginResult; @@ -714,183 +712,10 @@ // Make a copy of the entry and pare it down to only include the set // of requested attributes. Entry entryToReturn; boolean omitReal = isVirtualAttributesOnly(); boolean omitVirtual = isRealAttributesOnly(); if ((getAttributes() == null) || getAttributes().isEmpty()) { entryToReturn = entry.duplicateWithoutOperationalAttributes(typesOnly, omitReal, omitVirtual); } else { entryToReturn = entry.duplicateWithoutAttributes(); Entry entryToReturn = entry.filterEntry(getAttributes(), typesOnly, isVirtualAttributesOnly(), isRealAttributesOnly()); for (String attrName : getAttributes()) { if (attrName.equals("*")) { // This is a special placeholder indicating that all user attributes // should be returned. if (!omitReal) { if (typesOnly) { // First, add the placeholder for the objectclass // attribute. AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); List<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType)); entryToReturn.putAttribute(ocType, ocList); } else { // First, add the objectclass attribute. Attribute ocAttr = entry.getObjectClassAttribute(); if (ocAttr != null) { entryToReturn.replaceAttribute(ocAttr); } } } // Next iterate through all the user attributes and include them. for (AttributeType t : entry.getUserAttributes().keySet()) { List<Attribute> attrList = duplicateUserAttribute(entry, t, null, typesOnly, omitReal, omitVirtual); if (attrList != null) { entryToReturn.putAttribute(t, attrList); } } continue; } else if (attrName.equals("+")) { // This is a special placeholder indicating that all operational // attributes should be returned. for (AttributeType t : entry.getOperationalAttributes().keySet()) { List<Attribute> attrList = duplicateOperationalAttribute(entry, t, null, typesOnly, omitReal, omitVirtual); if (attrList != null) { entryToReturn.putAttribute(t, attrList); } } continue; } String lowerName; HashSet<String> options; int semicolonPos = attrName.indexOf(';'); if (semicolonPos > 0) { lowerName = toLowerCase(attrName.substring(0, semicolonPos)); int nextPos = attrName.indexOf(';', semicolonPos+1); options = new HashSet<String>(); while (nextPos > 0) { options.add(attrName.substring(semicolonPos+1, nextPos)); semicolonPos = nextPos; nextPos = attrName.indexOf(';', semicolonPos+1); } options.add(attrName.substring(semicolonPos+1)); } else { lowerName = toLowerCase(attrName); options = null; } AttributeType attrType = DirectoryServer.getAttributeType(lowerName); if (attrType == null) { boolean added = false; for (AttributeType t : entry.getUserAttributes().keySet()) { if (t.hasNameOrOID(lowerName)) { List<Attribute> attrList = duplicateUserAttribute(entry, t, options, typesOnly, omitReal, omitVirtual); if (attrList != null) { entryToReturn.putAttribute(t, attrList); added = true; break; } } } if (added) { continue; } for (AttributeType t : entry.getOperationalAttributes().keySet()) { if (t.hasNameOrOID(lowerName)) { List<Attribute> attrList = duplicateOperationalAttribute(entry, t, options, typesOnly, omitReal, omitVirtual); if (attrList != null) { entryToReturn.putAttribute(t, attrList); break; } } } } else { if (attrType.isObjectClassType()) { if (!omitReal) { if (typesOnly) { AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); List<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType)); entryToReturn.putAttribute(ocType, ocList); } else { List<Attribute> attrList = new ArrayList<Attribute>(1); attrList.add(entry.getObjectClassAttribute()); entryToReturn.putAttribute(attrType, attrList); } } } else { List<Attribute> attrList = duplicateOperationalAttribute(entry, attrType, options, typesOnly, omitReal, omitVirtual); if (attrList == null) { attrList = duplicateUserAttribute(entry, attrType, options, typesOnly, omitReal, omitVirtual); } if (attrList != null) { entryToReturn.putAttribute(attrType, attrList); } } } } } // If there is a matched values control, then further pare down the entry // based on the filters that it contains. @@ -1626,92 +1451,4 @@ ERR_SEARCH_BASE_DOESNT_EXIST.get(String.valueOf(getBaseDN())); appendErrorMessage(message); } // Copies non-empty attributes. private List<Attribute> duplicateAttribute( List<Attribute> attrList, Set<String> options, boolean omitValues, boolean omitReal, boolean omitVirtual) { if (attrList == null) { return null; } ArrayList<Attribute> duplicateList = new ArrayList<Attribute>(attrList.size()); for (Attribute a : attrList) { if (a.hasAllOptions(options)) { if (omitReal && !a.isVirtual()) { continue; } else if (omitVirtual && a.isVirtual()) { continue; } else if (a.isEmpty()) { continue; } else if (omitValues) { duplicateList.add(Attributes.empty(a)); } else { duplicateList.add(a); } } } if (duplicateList.isEmpty()) { return null; } else { return duplicateList; } } // Copy a user attribute - may return null if the attribute was // not found or if it was empty. private List<Attribute> duplicateUserAttribute( Entry entry, AttributeType attributeType, Set<String> options, boolean omitValues, boolean omitReal, boolean omitVirtual) { List<Attribute> currentList = entry.getUserAttribute(attributeType); return duplicateAttribute(currentList, options, omitValues, omitReal, omitVirtual); } // Copy an operational attribute - may return null if the // attribute was not found or if it was empty. private List<Attribute> duplicateOperationalAttribute( Entry entry, AttributeType attributeType, Set<String> options, boolean omitValues, boolean omitReal, boolean omitVirtual) { List<Attribute> currentList = entry.getOperationalAttribute(attributeType); return duplicateAttribute(currentList, options, omitValues, omitReal, omitVirtual); } } opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
@@ -22,7 +22,7 @@ * CDDL HEADER END * * * Copyright 2006-2008 Sun Microsystems, Inc. * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.protocols.ldap; @@ -149,12 +149,6 @@ attributes = new LinkedList<LDAPAttribute>(); Attribute ocAttr = searchEntry.getObjectClassAttribute(); if (ocAttr != null) { attributes.add(new LDAPAttribute(ocAttr)); } if (ldapVersion == 2) { // Merge attributes having the same type into a single @@ -281,6 +275,7 @@ * * @return The BER type for this protocol op. */ @Override public byte getType() { return OP_TYPE_SEARCH_RESULT_ENTRY; @@ -293,6 +288,7 @@ * * @return The name for this protocol op type. */ @Override public String getProtocolOpName() { return "Search Result Entry"; @@ -306,6 +302,7 @@ * * @return The ASN.1 element containing the encoded protocol op. */ @Override public ASN1Element encode() { ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2); @@ -422,6 +419,7 @@ * * @param buffer The buffer to which the string should be appended. */ @Override public void toString(StringBuilder buffer) { buffer.append("SearchResultEntry(dn="); @@ -453,6 +451,7 @@ * @param indent The number of spaces from the margin that the lines should * be indented. */ @Override public void toString(StringBuilder buffer, int indent) { StringBuilder indentBuf = new StringBuilder(indent); opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
@@ -34,6 +34,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -2884,69 +2885,6 @@ /** * Creates a duplicate of this entry without any operational * attributes that may be altered without impacting the * information in this entry. * <p> * TODO: this method is very specific to search result * processing but we are forced to have it here due to tight * coupling and performance reasons. * * @param typesOnly * Indicates whether to include attribute types only * without values. * @param omitReal * Indicates whether to exclude real attributes. * @param omitVirtual * Indicates whether to exclude virtual attributes. * @return A duplicate of this entry that may be altered without * impacting the information in this entry and that does not * contain any operational attributes. */ public Entry duplicateWithoutOperationalAttributes( boolean typesOnly, boolean omitReal, boolean omitVirtual) { HashMap<ObjectClass,String> objectClassesCopy; if (typesOnly || omitReal) { objectClassesCopy = new HashMap<ObjectClass,String>(0); } else { objectClassesCopy = new HashMap<ObjectClass,String>(objectClasses); } HashMap<AttributeType,List<Attribute>> userAttrsCopy = new HashMap<AttributeType,List<Attribute>>( userAttributes.size()); if (typesOnly && !omitReal) { // Make sure to include the objectClass attribute here because // it won't make it in otherwise. AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); ArrayList<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType)); userAttrsCopy.put(ocType, ocList); } deepCopy(userAttributes, userAttrsCopy, typesOnly, true, omitReal, omitVirtual); HashMap<AttributeType,List<Attribute>> operationalAttrsCopy = new HashMap<AttributeType,List<Attribute>>(0); Entry e = new Entry(dn, objectClassesCopy, userAttrsCopy, operationalAttrsCopy); return e; } /** * Performs a deep copy from the source map to the target map. * In this case, the attributes in the list will be duplicates * rather than re-using the same reference. @@ -3014,34 +2952,6 @@ /** * Creates a duplicate of this entry without any attribute or * objectclass information (i.e., it will just contain the DN and * placeholders for adding attributes) and objectclasses. * * @return A duplicate of this entry that may be altered without * impacting the information in this entry and that does * not contain attribute or objectclass information. */ public Entry duplicateWithoutAttributes() { HashMap<ObjectClass,String> objectClassesCopy = new HashMap<ObjectClass,String>(objectClasses.size()); HashMap<AttributeType,List<Attribute>> userAttrsCopy = new HashMap<AttributeType,List<Attribute>>( userAttributes.size()); HashMap<AttributeType,List<Attribute>> operationalAttrsCopy = new HashMap<AttributeType,List<Attribute>>( operationalAttributes.size()); return new Entry(dn, objectClassesCopy, userAttrsCopy, operationalAttrsCopy); } /** * Indicates whether this entry meets the criteria to consider it a * referral (e.g., it contains the "referral" objectclass and a * "ref" attribute). @@ -5782,7 +5692,8 @@ } } return; // Fall through - search results have an object attribute // as well. } List<Attribute> attributes; @@ -5875,5 +5786,411 @@ attributes.add(attribute); } /** * Returns an entry containing only those attributes of this entry * which match the provided criteria. * * @param attrNameList * The list of attributes to include, may include wild * cards. * @param omitValues * Indicates whether to omit attribute values when * processing. * @param omitReal * Indicates whether to exclude real attributes. * @param omitVirtual * Indicates whether to exclude virtual attributes. * @return An entry containing only those attributes of this entry * which match the provided criteria. */ public Entry filterEntry(Set<String> attrNameList, boolean omitValues, boolean omitReal, boolean omitVirtual) { HashMap<ObjectClass, String> objectClassesCopy; HashMap<AttributeType, List<Attribute>> userAttrsCopy; HashMap<AttributeType, List<Attribute>> operationalAttrsCopy; if (attrNameList == null || attrNameList.isEmpty()) { // Common case: return filtered user attributes. userAttrsCopy = new HashMap<AttributeType, List<Attribute>>(userAttributes .size()); operationalAttrsCopy = new HashMap<AttributeType, List<Attribute>>(0); if (omitReal) { objectClassesCopy = new HashMap<ObjectClass, String>(0); } else if (omitValues) { objectClassesCopy = new HashMap<ObjectClass, String>(0); // Add empty object class attribute. AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); ArrayList<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType)); userAttrsCopy.put(ocType, ocList); } else { objectClassesCopy = new HashMap<ObjectClass, String>(objectClasses); // First, add the objectclass attribute. Attribute ocAttr = getObjectClassAttribute(); if (ocAttr != null) { AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); ArrayList<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(ocAttr); userAttrsCopy.put(ocType, ocList); } } // Copy all user attributes. deepCopy(userAttributes, userAttrsCopy, omitValues, true, omitReal, omitVirtual); } else { // Incrementally build table of attributes. if (omitReal || omitValues) { objectClassesCopy = new HashMap<ObjectClass, String>(0); } else { objectClassesCopy = new HashMap<ObjectClass, String>(objectClasses.size()); } userAttrsCopy = new HashMap<AttributeType, List<Attribute>>(userAttributes .size()); operationalAttrsCopy = new HashMap<AttributeType, List<Attribute>>( operationalAttributes.size()); for (String attrName : attrNameList) { if (attrName.equals("*")) { // This is a special placeholder indicating that all user // attributes should be returned. if (!omitReal) { if (omitValues) { // Add empty object class attribute. AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); ArrayList<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType)); userAttrsCopy.put(ocType, ocList); } else { // Add the objectclass attribute. objectClassesCopy.putAll(objectClasses); Attribute ocAttr = getObjectClassAttribute(); if (ocAttr != null) { AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); ArrayList<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(ocAttr); userAttrsCopy.put(ocType, ocList); } } } // Copy all user attributes. deepCopy(userAttributes, userAttrsCopy, omitValues, true, omitReal, omitVirtual); continue; } else if (attrName.equals("+")) { // This is a special placeholder indicating that all // operational attributes should be returned. deepCopy(operationalAttributes, operationalAttrsCopy, omitValues, true, omitReal, omitVirtual); continue; } String lowerName; HashSet<String> options; int semicolonPos = attrName.indexOf(';'); if (semicolonPos > 0) { String tmpName = attrName.substring(0, semicolonPos); lowerName = toLowerCase(tmpName); int nextPos = attrName.indexOf(';', semicolonPos+1); options = new HashSet<String>(); while (nextPos > 0) { options.add(attrName.substring(semicolonPos+1, nextPos)); semicolonPos = nextPos; nextPos = attrName.indexOf(';', semicolonPos+1); } options.add(attrName.substring(semicolonPos+1)); attrName = tmpName; } else { lowerName = toLowerCase(attrName); options = null; } AttributeType attrType = DirectoryServer.getAttributeType(lowerName); if (attrType == null) { // Unrecognized attribute type - do best effort search. for (Map.Entry<AttributeType, List<Attribute>> e : userAttributes.entrySet()) { AttributeType t = e.getKey(); if (t.hasNameOrOID(lowerName)) { mergeAttributeLists(e.getValue(), userAttrsCopy, t, attrName, options, omitValues, omitReal, omitVirtual); continue; } } for (Map.Entry<AttributeType, List<Attribute>> e : operationalAttributes.entrySet()) { AttributeType t = e.getKey(); if (t.hasNameOrOID(lowerName)) { mergeAttributeLists(e.getValue(), userAttrsCopy, t, attrName, options, omitValues, omitReal, omitVirtual); continue; } } } else { // Recognized attribute type. if (attrType.isObjectClassType()) { if (!omitReal) { if (omitValues) { AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); List<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(Attributes.empty(ocType, attrName)); userAttrsCopy.put(ocType, ocList); } else { Attribute ocAttr = getObjectClassAttribute(); if (ocAttr != null) { AttributeType ocType = DirectoryServer.getObjectClassAttributeType(); if (!attrName.equals(ocAttr.getName())) { // User requested non-default object class type // name. AttributeBuilder builder = new AttributeBuilder(ocAttr); builder.setAttributeType(ocType, attrName); ocAttr = builder.toAttribute(); } List<Attribute> ocList = new ArrayList<Attribute>(1); ocList.add(ocAttr); userAttrsCopy.put(ocType, ocList); } } } } else { List<Attribute> attrList = getUserAttribute(attrType); if (attrList != null) { mergeAttributeLists(attrList, userAttrsCopy, attrType, attrName, options, omitValues, omitReal, omitVirtual); } else { attrList = getOperationalAttribute(attrType); if (attrList != null) { mergeAttributeLists(attrList, operationalAttrsCopy, attrType, attrName, options, omitValues, omitReal, omitVirtual); } } } } } } return new Entry(dn, objectClassesCopy, userAttrsCopy, operationalAttrsCopy); } /** * Copies the provided list of attributes into the destination * attribute map according to the provided criteria. * * @param sourceList * The list containing the attributes to be copied. * @param destMap * The map where the attributes should be copied to. * @param attrType * The attribute type. * @param attrName * The user-provided attribute name. * @param options * The user-provided attribute options. * @param omitValues * Indicates whether to exclude attribute values. * @param omitReal * Indicates whether to exclude real attributes. * @param omitVirtual * Indicates whether to exclude virtual attributes. */ private void mergeAttributeLists(List<Attribute> sourceList, HashMap<AttributeType, List<Attribute>> destMap, AttributeType attrType, String attrName, HashSet<String> options, boolean omitValues, boolean omitReal, boolean omitVirtual) { if (sourceList == null) { return; } for (Attribute attribute : sourceList) { if (attribute.isEmpty()) { continue; } else if (omitReal && !attribute.isVirtual()) { continue; } else if (omitVirtual && attribute.isVirtual()) { continue; } else if (!attribute.hasAllOptions(options)) { continue; } else { // If a non-default attribute name was provided or if the // attribute has options then we will need to rebuild the // attribute so that it contains the user-requested names and // options. AttributeType subAttrType = attribute.getAttributeType(); if ((attrName != null && !attrName.equals(attribute.getName())) || (options != null && !options.isEmpty())) { AttributeBuilder builder = new AttributeBuilder(); // We want to use the user-provided name only if this // attribute has the same type as the requested type. This // might not be the case for sub-types e.g. requesting // "name" and getting back "cn" - we don't want to rename // "name" to "cn". if (attrName == null || !subAttrType.equals(attrType)) { builder.setAttributeType(attribute.getAttributeType(), attribute.getName()); } else { builder.setAttributeType(attribute.getAttributeType(), attrName); } if (options != null) { builder.setOptions(options); } // Now add in remaining options from original attribute // (this will not overwrite options already present). builder.setOptions(attribute.getOptions()); if (!omitValues) { builder.addAll(attribute); } attribute = builder.toAttribute(); } else if (omitValues) { attribute = Attributes.empty(attribute); } // Now put the attribute into the destination map. // Be careful of duplicates. List<Attribute> attrList = destMap.get(subAttrType); if (attrList == null) { // Assume that they'll all go in the one list. This isn't // always the case, for example if the list contains // sub-types. attrList = new ArrayList<Attribute>(sourceList.size()); attrList.add(attribute); destMap.put(subAttrType, attrList); } else { // The attribute may have already been put in the list // - lets replace it assuming that the previous version // was added using a wildcard and that this version has // a user provided name and/or options. boolean found = false; for (int i = 0; i < attrList.size(); i++) { if (attrList.get(i).optionsEqual(attribute.getOptions())) { attrList.set(i, attribute); found = true; } } if (!found) { attrList.add(attribute); } } } } } } opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SearchOperationTestCase.java
@@ -45,13 +45,16 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.*; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.net.Socket; import java.io.IOException; @@ -390,8 +393,11 @@ Entry resultEntry = searchInternalForSingleEntry(searchOperation); assertEquals(resultEntry.getObjectClasses(), testEntry.getObjectClasses()); // Search results contain objectClass as an attribute. assertEquals(resultEntry.getUserAttributes().size(), testEntry.getUserAttributes().size()); testEntry.getUserAttributes().size() + 1); assertEquals(resultEntry.getOperationalAttributes().size(), 0); } @@ -485,8 +491,10 @@ assertEquals(resultEntry.getObjectClasses(), testEntry.getObjectClasses()); assertTrue(resultEntry.getOperationalAttributes().size() > 0); // Search results contain objectClass as an attribute. assertEquals(resultEntry.getUserAttributes().size(), testEntry.getUserAttributes().size()); testEntry.getUserAttributes().size() + 1); } @Test @@ -517,8 +525,11 @@ Entry resultEntry = searchInternalForSingleEntry(searchOperation); assertEquals(resultEntry.getObjectClasses(), testEntry.getObjectClasses()); // Search results contain objectClass as an attribute. assertEquals(resultEntry.getUserAttributes().size(), testEntry.getUserAttributes().size()); testEntry.getUserAttributes().size() + 1); assertEquals(resultEntry.getOperationalAttributes().size(), 1); } @@ -1143,4 +1154,187 @@ assertTrue(messages.isEmpty(), "Entry invalid: " + messages); } /** * Returns test data for testSearchInternalUserAttributeNames. * * @return The test data. */ @DataProvider(name = "testSearchInternalUserAttributeNames") public Object[][] createTestSearchInternalUserAttributeNamesData() { // First array is the requested attributes. // Second array is the expected attribute names in the entry. return new Object[][] { { Arrays.<String>asList(), Arrays.asList("objectClass", "cn", "cn;lang-fr") }, { Arrays.asList("*", "+"), Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp") }, { Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp"), Arrays.asList("objectClass", "cn", "cn;lang-fr", "entryDN", "createTimestamp") }, { Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP"), Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") }, { Arrays.asList("*", "+", "OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP"), Arrays.asList("OBJECTCLASS", "commonName", "commonName;LANG-FR", "entrydn", "CREATETIMESTAMP") }, { Arrays.asList("name"), Arrays.asList("givenName", "sn", "cn", "cn;lang-fr") }, { Arrays.asList("name;lang-fr"), Arrays.asList("cn;lang-fr") }, { Arrays.asList("name;LANG-FR"), Arrays.asList("cn;LANG-FR") }, }; } /** * Tests that attributes are returned from internal searches using the * attribute name requested by the user. * * @param requestedAttributes * The list of requested attributes names. * @param expectedAttributes * The list of expected attribute names. * @throws Exception * If an unexpected problem occurs. */ @Test(dataProvider = "testSearchInternalUserAttributeNames") public void testSearchInternalUserAttributeNames( List<String> requestedAttributes, List<String> expectedAttributes) throws Exception { TestCaseUtils.initializeTestBackend(true); String userDNString = "uid=test.user,o=test"; DN userDN = DN.decode(userDNString); TestCaseUtils.addEntry("dn: " + userDNString, "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.user", "givenName: Test", "sn: User", "cn: Test User", "cn;lang-fr: Test Usager", "userPassword: password"); Entry userEntry = DirectoryServer.getEntry(userDN); assertNotNull(userEntry); LinkedHashSet<String> attributes = new LinkedHashSet<String>(requestedAttributes); InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalSearchOperation search = conn.processSearch(userDNString, SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES, 0, // Size limit 0, // Time limit false, // Types only "(objectClass=*)", attributes); assertEquals(search.getResultCode(), ResultCode.SUCCESS); LinkedList<SearchResultEntry> entries = search.getSearchEntries(); assertEquals(entries.size(), 1); Entry entry = entries.getFirst(); assertEquals(entry.getDN(), userDN); // Check all expected attributes are present and have // the user requested name. List<Attribute> attrList = entry.getAttributes(); Set<String> actualNames = new HashSet<String>(); for (Attribute attribute : attrList) { actualNames.add(attribute.getNameWithOptions()); } assertTrue(actualNames.containsAll(expectedAttributes), "Expected: " + expectedAttributes + " got " + actualNames); } /** * Tests that attributes are returned from external searches using the * attribute name requested by the user. * * @param requestedAttributes * The list of requested attributes names. * @param expectedAttributes * The list of expected attribute names. * @throws Exception * If an unexpected problem occurs. */ @Test(dataProvider = "testSearchInternalUserAttributeNames") public void testSearchExternalUserAttributeNames( List<String> requestedAttributes, List<String> expectedAttributes) throws Exception { TestCaseUtils.initializeTestBackend(true); String userDNString = "uid=test.user,o=test"; DN userDN = DN.decode(userDNString); TestCaseUtils.addEntry("dn: " + userDNString, "objectClass: top", "objectClass: person", "objectClass: organizationalPerson", "objectClass: inetOrgPerson", "uid: test.user", "givenName: Test", "sn: User", "cn: Test User", "cn;lang-fr: Test Usager", "userPassword: password"); Entry userEntry = DirectoryServer.getEntry(userDN); assertNotNull(userEntry); LinkedHashSet<String> attributes = new LinkedHashSet<String>(requestedAttributes); SearchRequestProtocolOp searchRequest = new SearchRequestProtocolOp( new ASN1OctetString(userDNString), SearchScope.BASE_OBJECT, DereferencePolicy.NEVER_DEREF_ALIASES, Integer.MAX_VALUE, Integer.MAX_VALUE, false, LDAPFilter.decode("(objectclass=*)"), attributes); SearchResultEntryProtocolOp entry = searchExternalForSingleEntry(searchRequest, null); assertEquals(entry.getDN(), userDN); // Check all expected attributes are present and have // the user requested name. LinkedList<LDAPAttribute> attrList = entry.getAttributes(); Set<String> actualNames = new HashSet<String>(); for (LDAPAttribute attribute : attrList) { actualNames.add(attribute.getAttributeType()); } assertTrue(actualNames.containsAll(expectedAttributes), "Expected: " + expectedAttributes + " got " + actualNames); } }