use of javax.naming.ldap.PagedResultsResponseControl in project Openfire by igniterealtime.
the class LdapManager method retrieveList.
/**
* Generic routine for retrieving a list of results from the LDAP server. It's meant to be very
* flexible so that just about any query for a list of results can make use of it without having
* to reimplement their own calls to LDAP. This routine also accounts for sorting settings,
* paging settings, any other global settings, and alternate DNs.
*
* The passed in filter string needs to be pre-prepared! In other words, nothing will be changed
* in the string before it is used as a string.
*
* @param attribute LDAP attribute to be pulled from each result and placed in the return results.
* Typically pulled from this manager.
* @param searchFilter Filter to use to perform the search. Typically pulled from this manager.
* @param startIndex Number/index of first result to include in results. (-1 for no limit)
* @param numResults Number of results to include. (-1 for no limit)
* @param suffixToTrim An arbitrary string to trim from the end of every attribute returned. null to disable.
* @param escapeJIDs Use JID-escaping for returned results (e.g. usernames)
* @return A simple list of strings (that should be sorted) of the results.
*/
public List<String> retrieveList(String attribute, String searchFilter, int startIndex, int numResults, String suffixToTrim, boolean escapeJIDs) {
List<String> results = new ArrayList<>();
int pageSize = -1;
String pageSizeStr = properties.get("ldap.pagedResultsSize");
if (pageSizeStr != null) {
try {
pageSize = Integer.parseInt(pageSizeStr);
/* radix -1 is invalid */
} catch (NumberFormatException e) {
// poorly formatted number, ignoring
}
}
Boolean clientSideSort = false;
String clientSideSortStr = properties.get("ldap.clientSideSorting");
if (clientSideSortStr != null) {
clientSideSort = Boolean.valueOf(clientSideSortStr);
}
LdapContext ctx = null;
LdapContext ctx2 = null;
try {
ctx = getContext(baseDN);
// Set up request controls, if appropriate.
List<Control> baseTmpRequestControls = new ArrayList<>();
if (!clientSideSort) {
// Server side sort on username field.
baseTmpRequestControls.add(new SortControl(new String[] { attribute }, Control.NONCRITICAL));
}
if (pageSize > 0) {
// Server side paging.
baseTmpRequestControls.add(new PagedResultsControl(pageSize, Control.NONCRITICAL));
}
Control[] baseRequestControls = baseTmpRequestControls.toArray(new Control[baseTmpRequestControls.size()]);
ctx.setRequestControls(baseRequestControls);
SearchControls searchControls = new SearchControls();
// See if recursive searching is enabled. Otherwise, only search one level.
if (isSubTreeSearch()) {
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
} else {
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
}
searchControls.setReturningAttributes(new String[] { attribute });
// If server side sort, we'll skip the initial ones we don't want, and stop when we've hit
// the amount we do want.
int skip = -1;
int lastRes = -1;
if (!clientSideSort) {
if (startIndex != -1) {
skip = startIndex;
}
if (numResults != -1) {
lastRes = startIndex + numResults;
}
}
byte[] cookie;
int count = 0;
// Run through all pages of results (one page is also possible ;) )
do {
cookie = null;
NamingEnumeration<SearchResult> answer = ctx.search("", searchFilter, searchControls);
// Examine all of the results on this page
while (answer.hasMoreElements()) {
count++;
if (skip > 0 && count <= skip) {
answer.next();
continue;
}
if (lastRes != -1 && count > lastRes) {
answer.next();
break;
}
// Get the next result.
String result = (String) answer.next().getAttributes().get(attribute).get();
// Remove suffixToTrim if set
if (suffixToTrim != null && suffixToTrim.length() > 0 && result.endsWith(suffixToTrim)) {
result = result.substring(0, result.length() - suffixToTrim.length());
}
// Add this to the result.
results.add(escapeJIDs ? JID.escapeNode(result) : result);
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// Close the enumeration.
answer.close();
// Re-activate paged results; affects nothing if no paging support
List<Control> tmpRequestControls = new ArrayList<>();
if (!clientSideSort) {
// Server side sort on username field.
tmpRequestControls.add(new SortControl(new String[] { attribute }, Control.NONCRITICAL));
}
if (pageSize > 0) {
// Server side paging.
tmpRequestControls.add(new PagedResultsControl(pageSize, cookie, Control.CRITICAL));
}
Control[] requestControls = tmpRequestControls.toArray(new Control[tmpRequestControls.size()]);
ctx.setRequestControls(requestControls);
} while (cookie != null && (lastRes == -1 || count <= lastRes));
// Add groups found in alternate DN
if (alternateBaseDN != null && (lastRes == -1 || count <= lastRes)) {
ctx2 = getContext(alternateBaseDN);
ctx2.setRequestControls(baseRequestControls);
// Run through all pages of results (one page is also possible ;) )
do {
cookie = null;
NamingEnumeration<SearchResult> answer = ctx2.search("", searchFilter, searchControls);
// Examine all of the results on this page
while (answer.hasMoreElements()) {
count++;
if (skip > 0 && count <= skip) {
answer.next();
continue;
}
if (lastRes != -1 && count > lastRes) {
answer.next();
break;
}
// Get the next result.
String result = (String) answer.next().getAttributes().get(attribute).get();
// Remove suffixToTrim if set
if (suffixToTrim != null && suffixToTrim.length() > 0 && result.endsWith(suffixToTrim)) {
result = result.substring(0, result.length() - suffixToTrim.length());
}
// Add this to the result.
results.add(escapeJIDs ? JID.escapeNode(result) : result);
}
// Examine the paged results control response
Control[] controls = ctx2.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// Close the enumeration.
answer.close();
// Re-activate paged results; affects nothing if no paging support
List<Control> tmpRequestControls = new ArrayList<>();
if (!clientSideSort) {
// Server side sort on username field.
tmpRequestControls.add(new SortControl(new String[] { attribute }, Control.NONCRITICAL));
}
if (pageSize > 0) {
// Server side paging.
tmpRequestControls.add(new PagedResultsControl(pageSize, cookie, Control.CRITICAL));
}
Control[] requestControls = tmpRequestControls.toArray(new Control[tmpRequestControls.size()]);
ctx2.setRequestControls(requestControls);
} while (cookie != null && (lastRes == -1 || count <= lastRes));
}
// If client-side sorting is enabled, sort and trim.
if (clientSideSort) {
Collections.sort(results);
if (startIndex != -1 || numResults != -1) {
if (startIndex == -1) {
startIndex = 0;
}
if (numResults == -1) {
numResults = results.size();
}
int endIndex = Math.min(startIndex + numResults, results.size() - 1);
results = results.subList(startIndex, endIndex);
}
}
} catch (Exception e) {
Log.error(e.getMessage(), e);
} finally {
try {
if (ctx != null) {
ctx.setRequestControls(null);
ctx.close();
}
if (ctx2 != null) {
ctx2.setRequestControls(null);
ctx2.close();
}
} catch (Exception ignored) {
// Ignore.
}
}
return results;
}
use of javax.naming.ldap.PagedResultsResponseControl in project Openfire by igniterealtime.
the class LdapManager method retrieveListCount.
/**
* Generic routine for retrieving the number of available results from the LDAP server that
* match the passed search filter. This routine also accounts for paging settings and
* alternate DNs.
*
* The passed in filter string needs to be pre-prepared! In other words, nothing will be changed
* in the string before it is used as a string.
*
* @param attribute LDAP attribute to be pulled from each result and used in the query.
* Typically pulled from this manager.
* @param searchFilter Filter to use to perform the search. Typically pulled from this manager.
* @return The number of entries that match the filter.
*/
public Integer retrieveListCount(String attribute, String searchFilter) {
int pageSize = -1;
String pageSizeStr = properties.get("ldap.pagedResultsSize");
if (pageSizeStr != null) {
try {
pageSize = Integer.parseInt(pageSizeStr);
/* radix -1 is invalid */
} catch (NumberFormatException e) {
// poorly formatted number, ignoring
}
}
LdapContext ctx = null;
LdapContext ctx2 = null;
Integer count = 0;
try {
ctx = getContext(baseDN);
// Set up request controls, if appropriate.
List<Control> baseTmpRequestControls = new ArrayList<>();
if (pageSize > 0) {
// Server side paging.
baseTmpRequestControls.add(new PagedResultsControl(pageSize, Control.NONCRITICAL));
}
Control[] baseRequestControls = baseTmpRequestControls.toArray(new Control[baseTmpRequestControls.size()]);
ctx.setRequestControls(baseRequestControls);
SearchControls searchControls = new SearchControls();
// See if recursive searching is enabled. Otherwise, only search one level.
if (isSubTreeSearch()) {
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
} else {
searchControls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
}
searchControls.setReturningAttributes(new String[] { attribute });
byte[] cookie;
// Run through all pages of results (one page is also possible ;) )
do {
cookie = null;
NamingEnumeration<SearchResult> answer = ctx.search("", searchFilter, searchControls);
// Examine all of the results on this page
while (answer.hasMoreElements()) {
answer.next();
count++;
}
// Examine the paged results control response
Control[] controls = ctx.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// Close the enumeration.
answer.close();
// Re-activate paged results; affects nothing if no paging support
List<Control> tmpRequestControls = new ArrayList<>();
if (pageSize > 0) {
// Server side paging.
tmpRequestControls.add(new PagedResultsControl(pageSize, cookie, Control.CRITICAL));
}
Control[] requestControls = tmpRequestControls.toArray(new Control[tmpRequestControls.size()]);
ctx.setRequestControls(requestControls);
} while (cookie != null);
// Add groups found in alternate DN
if (alternateBaseDN != null) {
ctx2 = getContext(alternateBaseDN);
ctx2.setRequestControls(baseRequestControls);
// Run through all pages of results (one page is also possible ;) )
do {
cookie = null;
NamingEnumeration<SearchResult> answer = ctx2.search("", searchFilter, searchControls);
// Examine all of the results on this page
while (answer.hasMoreElements()) {
answer.next();
count++;
}
// Examine the paged results control response
Control[] controls = ctx2.getResponseControls();
if (controls != null) {
for (Control control : controls) {
if (control instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) control;
cookie = prrc.getCookie();
}
}
}
// Close the enumeration.
answer.close();
// Re-activate paged results; affects nothing if no paging support
List<Control> tmpRequestControls = new ArrayList<>();
if (pageSize > 0) {
// Server side paging.
tmpRequestControls.add(new PagedResultsControl(pageSize, cookie, Control.CRITICAL));
}
Control[] requestControls = tmpRequestControls.toArray(new Control[tmpRequestControls.size()]);
ctx2.setRequestControls(requestControls);
} while (cookie != null);
}
} catch (Exception e) {
Log.error(e.getMessage(), e);
} finally {
try {
if (ctx != null) {
ctx.setRequestControls(null);
ctx.close();
}
if (ctx2 != null) {
ctx2.setRequestControls(null);
ctx2.close();
}
} catch (Exception ignored) {
// Ignore.
}
}
return count;
}
use of javax.naming.ldap.PagedResultsResponseControl in project camel by apache.
the class LdapProducer method prepareNextPage.
private boolean prepareNextPage(LdapContext ldapContext) throws Exception {
Control[] responseControls = ldapContext.getResponseControls();
byte[] cookie = null;
if (responseControls != null) {
for (Control responseControl : responseControls) {
if (responseControl instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) responseControl;
cookie = prrc.getCookie();
}
}
}
if (cookie == null) {
return false;
} else {
ldapContext.setRequestControls(new Control[] { new PagedResultsControl(pageSize, cookie, Control.CRITICAL) });
return true;
}
}
use of javax.naming.ldap.PagedResultsResponseControl in project ranger by apache.
the class LdapDeltaUserGroupBuilder method getGroups.
private void getGroups(UserGroupSink sink) throws Throwable {
NamingEnumeration<SearchResult> groupSearchResultEnum = null;
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddhhmmss");
long highestdeltaSyncGroupTime = deltaSyncGroupTime;
try {
createLdapContext();
int total;
// Activate paged results
if (pagedResultsEnabled) {
ldapContext.setRequestControls(new Control[] { new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
}
extendedGroupSearchFilter = "(objectclass=" + groupObjectClass + ")";
if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
String customFilter = groupSearchFilter.trim();
if (!customFilter.startsWith("(")) {
customFilter = "(" + customFilter + ")";
}
extendedGroupSearchFilter = extendedGroupSearchFilter + customFilter;
}
extendedAllGroupsSearchFilter = "(&" + extendedGroupSearchFilter + "(|(uSNChanged>=" + deltaSyncGroupTime + ")(modifyTimestamp>=" + deltaSyncGroupTimeStamp + "Z)))";
LOG.info("extendedAllGroupsSearchFilter = " + extendedAllGroupsSearchFilter);
for (int ou = 0; ou < groupSearchBase.length; ou++) {
byte[] cookie = null;
int counter = 0;
try {
int paged = 0;
do {
groupSearchResultEnum = ldapContext.search(groupSearchBase[ou], extendedAllGroupsSearchFilter, groupSearchControls);
while (groupSearchResultEnum.hasMore()) {
final SearchResult groupEntry = groupSearchResultEnum.next();
if (groupEntry == null) {
if (LOG.isInfoEnabled()) {
LOG.info("groupEntry null, skipping sync for the entry");
}
continue;
}
counter++;
noOfGroups++;
Attribute groupNameAttr = groupEntry.getAttributes().get(groupNameAttribute);
if (groupNameAttr == null) {
if (LOG.isInfoEnabled()) {
LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() + ", skipping sync");
}
continue;
}
String gName = (String) groupNameAttr.get();
String transformGroupName = groupNameTransform(gName);
// check for group members and populate userInfo object with user's full name and group mapping
if (groupSearchFirstEnabled) {
LOG.debug("Update Ranger admin with " + transformGroupName);
sink.addOrUpdateGroup(transformGroupName);
}
Attribute timeStampAttr = groupEntry.getAttributes().get("uSNChanged");
if (timeStampAttr != null) {
String uSNChangedVal = (String) timeStampAttr.get();
long currentDeltaSyncTime = Long.parseLong(uSNChangedVal);
if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
highestdeltaSyncGroupTime = currentDeltaSyncTime;
}
} else {
timeStampAttr = groupEntry.getAttributes().get("modifytimestamp");
if (timeStampAttr != null) {
String timeStampVal = (String) timeStampAttr.get();
Date parseDate = dateFormat.parse(timeStampVal);
long currentDeltaSyncTime = parseDate.getTime();
LOG.info("timeStampVal = " + timeStampVal + "and currentDeltaSyncTime = " + currentDeltaSyncTime);
if (currentDeltaSyncTime > highestdeltaSyncGroupTime) {
highestdeltaSyncGroupTime = currentDeltaSyncTime;
deltaSyncGroupTimeStamp = timeStampVal;
}
}
}
Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
int userCount = 0;
if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
LOG.info("No members available for " + gName);
continue;
}
NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
while (userEnum.hasMore()) {
String originalUserFullName = (String) userEnum.next();
if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
continue;
}
userCount++;
String userName = getShortUserName(originalUserFullName);
originalUserFullName = originalUserFullName.toLowerCase();
if (groupSearchFirstEnabled && !userSearchEnabled) {
String transformUserName = userNameTransform(userName);
try {
sink.addOrUpdateUser(transformUserName);
} catch (Throwable t) {
LOG.error("sink.addOrUpdateUser failed with exception: " + t.getMessage() + ", for user: " + transformUserName);
}
userNameMap.put(originalUserFullName, transformUserName);
noOfUsers++;
}
// System.out.println("Adding " + userNameMap.get(originalUserFullName) + " and fullname = " + originalUserFullName + " to " + gName);
if (userNameMap.get(originalUserFullName) != null) {
groupUserTable.put(gName, originalUserFullName, userNameMap.get(originalUserFullName));
} else {
groupUserTable.put(gName, originalUserFullName, originalUserFullName);
}
groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
}
LOG.info("No. of members in the group " + gName + " = " + userCount);
}
// Examine the paged results control response
Control[] controls = ldapContext.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
total = prrc.getResultSize();
if (total != 0) {
LOG.debug("END-OF-PAGE total : " + total);
} else {
LOG.debug("END-OF-PAGE total : unknown");
}
cookie = prrc.getCookie();
}
}
} else {
LOG.debug("No controls were sent from the server");
}
// Re-activate paged results
if (pagedResultsEnabled) {
LOG.debug(String.format("Fetched paged results round: %s", ++paged));
ldapContext.setRequestControls(new Control[] { new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
}
} while (cookie != null);
LOG.info("LdapDeltaUserGroupBuilder.getGroups() completed with group count: " + counter);
} catch (Exception t) {
LOG.error("LdapDeltaUserGroupBuilder.getGroups() failed with exception: " + t);
LOG.info("LdapDeltaUserGroupBuilder.getGroups() group count: " + counter);
}
}
} finally {
if (groupSearchResultEnum != null) {
groupSearchResultEnum.close();
}
closeLdapContext();
}
if (groupHierarchyLevels > 0) {
LOG.debug("deltaSyncGroupTime = " + deltaSyncGroupTime);
if (deltaSyncGroupTime > 0) {
LOG.info("LdapDeltaUserGroupBuilder.getGroups(): Going through group hierarchy for nested group evaluation for deltasync");
goUpGroupHierarchyLdap(groupNameMap.keySet(), groupHierarchyLevels - 1);
}
}
if (deltaSyncGroupTime < highestdeltaSyncGroupTime) {
// Incrementing highestdeltaSyncGroupTime (for AD) in order to avoid search record repetition for next sync cycle.
deltaSyncGroupTime = highestdeltaSyncGroupTime + 1;
// Incrementing the highest timestamp value (for OpenLdap) with 1min in order to avoid search record repetition for next sync cycle.
deltaSyncGroupTimeStamp = dateFormat.format(new Date(highestdeltaSyncGroupTime + 60000l));
}
}
use of javax.naming.ldap.PagedResultsResponseControl in project ranger by apache.
the class LdapDeltaUserGroupBuilder method goUpGroupHierarchyLdap.
private void goUpGroupHierarchyLdap(Set<String> groupDNs, int groupHierarchyLevels) throws Throwable {
if (groupHierarchyLevels <= 0 || groupDNs.isEmpty()) {
return;
}
Set<String> nextLevelGroups = new HashSet<String>();
NamingEnumeration<SearchResult> groupSearchResultEnum = null;
try {
createLdapContext();
int total;
// Activate paged results
if (pagedResultsEnabled) {
ldapContext.setRequestControls(new Control[] { new PagedResultsControl(pagedResultsSize, Control.NONCRITICAL) });
}
String groupFilter = "(&(objectclass=" + groupObjectClass + ")";
if (groupSearchFilter != null && !groupSearchFilter.trim().isEmpty()) {
String customFilter = groupSearchFilter.trim();
if (!customFilter.startsWith("(")) {
customFilter = "(" + customFilter + ")";
}
groupFilter += customFilter + "(|";
}
StringBuilder filter = new StringBuilder();
for (String groupDN : groupDNs) {
filter.append("(").append(groupMemberAttributeName).append("=").append(groupDN).append(")");
}
filter.append("))");
groupFilter += filter;
LOG.info("extendedAllGroupsSearchFilter = " + groupFilter);
for (int ou = 0; ou < groupSearchBase.length; ou++) {
byte[] cookie = null;
int counter = 0;
try {
do {
groupSearchResultEnum = ldapContext.search(groupSearchBase[ou], groupFilter, groupSearchControls);
while (groupSearchResultEnum.hasMore()) {
final SearchResult groupEntry = groupSearchResultEnum.next();
if (groupEntry == null) {
if (LOG.isInfoEnabled()) {
LOG.info("groupEntry null, skipping sync for the entry");
}
continue;
}
counter++;
Attribute groupNameAttr = groupEntry.getAttributes().get(groupNameAttribute);
if (groupNameAttr == null) {
if (LOG.isInfoEnabled()) {
LOG.info(groupNameAttribute + " empty for entry " + groupEntry.getNameInNamespace() + ", skipping sync");
}
continue;
}
nextLevelGroups.add(groupEntry.getNameInNamespace());
String gName = (String) groupNameAttr.get();
Attribute groupMemberAttr = groupEntry.getAttributes().get(groupMemberAttributeName);
int userCount = 0;
if (groupMemberAttr == null || groupMemberAttr.size() <= 0) {
LOG.info("No members available for " + gName);
continue;
}
NamingEnumeration<?> userEnum = groupMemberAttr.getAll();
while (userEnum.hasMore()) {
String originalUserFullName = (String) userEnum.next();
if (originalUserFullName == null || originalUserFullName.trim().isEmpty()) {
continue;
}
userCount++;
originalUserFullName = originalUserFullName.toLowerCase();
if (userNameMap.get(originalUserFullName) != null) {
groupUserTable.put(gName, originalUserFullName, userNameMap.get(originalUserFullName));
} else {
groupUserTable.put(gName, originalUserFullName, originalUserFullName);
}
groupNameMap.put(groupEntry.getNameInNamespace().toLowerCase(), gName);
}
LOG.info("No. of members in the group " + gName + " = " + userCount);
}
// Examine the paged results control response
Control[] controls = ldapContext.getResponseControls();
if (controls != null) {
for (int i = 0; i < controls.length; i++) {
if (controls[i] instanceof PagedResultsResponseControl) {
PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
total = prrc.getResultSize();
if (total != 0) {
LOG.debug("END-OF-PAGE total : " + total);
} else {
LOG.debug("END-OF-PAGE total : unknown");
}
cookie = prrc.getCookie();
}
}
} else {
LOG.debug("No controls were sent from the server");
}
// Re-activate paged results
if (pagedResultsEnabled) {
ldapContext.setRequestControls(new Control[] { new PagedResultsControl(pagedResultsSize, cookie, Control.CRITICAL) });
}
} while (cookie != null);
LOG.info("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() completed with group count: " + counter);
} catch (RuntimeException re) {
LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with runtime exception: ", re);
throw re;
} catch (Exception t) {
LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with exception: ", t);
LOG.info("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() group count: " + counter);
}
}
} catch (RuntimeException re) {
LOG.error("LdapDeltaUserGroupBuilder.goUpGroupHierarchyLdap() failed with exception: ", re);
throw re;
} finally {
if (groupSearchResultEnum != null) {
groupSearchResultEnum.close();
}
closeLdapContext();
}
goUpGroupHierarchyLdap(nextLevelGroups, groupHierarchyLevels - 1);
}
Aggregations