Thursday, May 21, 2009

Java - how to keep your instance NamingEnumeration object and iterate through it without .next() killing it


Problem: You have a NamingEnumeration and want to keep untouched, while passing it to different methods that need to iterate through it. Error: doing a namingOperation.next() walks the object, and when you reach the end, there's no .moveToFront() method, which allows you to re-use the NamingEnumeration object.

Solution: use Collections.list( namingEnumeration ), which returns an ArrayList. Then, instantiate a new copy of the original ArrayList and then use this copy, with an Iterator, walking each element of the arrayList object.

The example below is of a NamingEnumeration A which is made up of many NamingEnumerations B, which are made up of some NamingEnumerations C. (basically it's an LDAP naming enumeration result after performing a dirContext.search( ... )


See, this won't work:

public static void printAllAttributes( NamingEnumeration originalNamingEnumeration )


// used only to create copy
ArrayList arrayListBackup = Collections.list( originalNamingEnumeration );

// create copy
ArrayList arrayList = new ArrayList( arrayListBackup );
...
because the originalNamingEnumeration gets "exhausted" after Collections.list() is called.
So, your only option is to get the original NamingEnumeration, convert it to an ArrayList:

NamingEnumeration namingEnumeration = dirContext.search( searchBase, searchFilter, searchControls );
ArrayList tempArrayList = Collections.list( namingEnumeration );
and forget about it:

namingEnumeration.close();
namingEnumeration = null;
Then, make as many copies of that tempArrayList, and use those copies:

ArrayList arrayListCopy1 = new ArrayList( tempArrayList );
... do whatever
ArrayList arrayListCopy2 = new ArrayList( tempArrayList );
... do whatever
ArrayList arrayListCopy3 = new ArrayList( tempArrayList );
In my case, I want to keep the search results of an LDAP query, which is stored
in a NamingEnumeration, and then call different methods on the search results,
which iterate on the NamingEnumeration, screwing it up. So, keeping the search results
in a globally defined ArrayList object allows me to use it later. Final search routing looks as such:


public int search( String searchBase, String searchFilter )
{
SearchControls searchControls = new SearchControls();
searchControls.setSearchScope( SearchControls.SUBTREE_SCOPE );
try
{
NamingEnumeration namingEnumeration = dirContext.search( searchBase, searchFilter, searchControls );
ArrayList tempArrayList = Collections.list( namingEnumeration );
namingEnumeration.close();
namingEnumeration = null;

this.lastSearchResultArrayList = new ArrayList( tempArrayList );
tempArrayList = null;
}
catch ( NamingException e )
{
logerror("Error while searching: " + e.toString() );
return -1;
}
return 0;
}

No comments:

Post a Comment