DynamicGroupMemberList.java revision ea1068c292e9b341af6d6b563cd8988a96be20a9
/*
* 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 legal-notices/CDDLv1_0.txt
* 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 legal-notices/CDDLv1_0.txt.
* 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 2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
/**
* This class defines a mechanism that may be used to iterate over the
* members of a dynamic group, optionally using an additional set of
* criteria to further filter the results.
*/
public class DynamicGroupMemberList
extends MemberList
{
// Indicates whether the search thread has completed its processing.
private boolean searchesCompleted;
// The base DN to use when filtering the set of group members.
// The DN of the entry containing the group definition.
// The queue into which results will be placed while they are waiting to be
// returned. The types of objects that may be placed in this queue are Entry
// objects to return or MembershipException objects to throw.
// The search filter to use when filtering the set of group members.
private final SearchFilter filter;
// The search scope to use when filtering the set of group members.
private final SearchScope scope;
// The set of LDAP URLs that define the membership criteria.
/**
* Creates a new dynamic group member list with the provided information.
*
* @param groupDN The DN of the entry containing the group definition.
* @param memberURLs The set of LDAP URLs that define the membership
* criteria for the associated group.
*
* @throws DirectoryException If a problem occurs while creating the member
* list.
*/
throws DirectoryException
{
}
/**
* Creates a new dynamic group member list with the provided information.
*
* @param groupDN The DN of the entry containing the group definition.
* @param memberURLs The set of LDAP URLs that define the membership
* criteria for the associated group.
* @param baseDN The base DN that should be enforced for all entries to
* return.
* @param scope The scope that should be enforced for all entries to
* return.
* @param filter The filter that should be enforced for all entries to
* return.
*
* @throws DirectoryException If a problem occurs while creating the member
* list.
*/
throws DirectoryException
{
this.memberURLs = memberURLs;
{
}
else
{
}
searchesCompleted = false;
// We're going to have to perform one or more internal searches in order to
// get the results. We need to be careful about the way that we construct
// them in order to avoid the possibility of getting duplicate results, so
// searches with overlapping bases will need to be combined.
{
// First, determine the base DN for the search. It needs to be evaluated
// as relative to both the overall base DN specified in the set of
// criteria, as well as any other existing base DNs in the same hierarchy.
{
{
// The base DN requested by the user is below the base DN for this
// URL, so we'll use the base DN requested by the user.
}
{
// The base DN from the URL is outside the base requested by the user,
// so we can skip this URL altogether.
continue;
}
}
// If this is the first URL, then we can just add it with the base DN.
// Otherwise, we need to see if it needs to be merged with other URLs in
// the same hierarchy.
{
}
else
{
// See if the specified base DN is already in the map. If so, then
// just add the new URL to the existing list.
{
// There's no existing list for the same base DN, but there might be
// DNs in an overlapping hierarchy. If so, then use the base DN that
// is closest to the naming context. If not, then add a new list with
// the current base DN.
boolean found = false;
{
{
// The base DN for the current URL is below an existing base DN,
// so we can just add this URL to the existing list and be done.
found = true;
break;
}
{
// The base DN for the current URL is above the existing base DN,
// so we should use the base DN for the current URL instead of the
// existing one.
found = true;
break;
}
}
if (! found)
{
}
}
else
{
// There was already a list with the same base DN, so just add the
// URL.
}
}
}
// At this point, we should know what base DN(s) we need to use, so we can
// create the filter to use with that base DN. There are some special-case
// optimizations that we can do here, but in general the filter will look
// like "(&(filter)(|(urlFilters)))".
{
new LinkedHashSet<SearchFilter>();
{
}
{
{
}
else
{
}
}
else
{
{
{
}
else
{
new LinkedHashSet<SearchFilter>();
}
}
else
{
{
}
else
{
new LinkedHashSet<SearchFilter>();
}
}
}
}
// At this point, we should have all the information we need to perform the
// searches. Create arrays of the elements for each.
{
int j=0;
{
}
}
}
/**
* Retrieves the DN of the dynamic group with which this dynamic group member
* list is associated.
*
* @return The DN of the dynamic group with which this dynamic group member
* list is associated.
*/
public final DN getDynamicGroupDN()
{
return groupDN;
}
/**
* Indicates that all of the searches needed to iterate across the member list
* have completed and there will not be any more results provided.
*/
final void setSearchesCompleted()
{
searchesCompleted = true;
}
/**
* Adds the provided entry to the set of results that should be returned for
* this member list.
*
* @param entry The entry to add to the set of results that should be
* returned for this member list.
*
* @return {@code true} if the entry was added to the result set, or
* {@code false} if it was not (either because a timeout expired or
* the attempt was interrupted). If this method returns
* {@code false}, then the search thread should terminate
* immediately.
*/
{
try
{
}
catch (InterruptedException ie)
{
return false;
}
}
/**
* Adds the provided membership exception so that it will be thrown along with
* the set of results for this member list.
*
* @param membershipException The membership exception to be thrown.
*
* @return {@code true} if the exception was added to the result set, or
* {@code false} if it was not (either because a timeout expired or
* the attempt was interrupted). If this method returns
* {@code false}, then the search thread should terminate
* immediately.
*/
{
try
{
}
catch (InterruptedException ie)
{
return false;
}
}
/**
* {@inheritDoc}
*/
public boolean hasMoreMembers()
{
while (! searchesCompleted)
{
{
return true;
}
try
{
} catch (Exception e) {}
}
}
/**
* {@inheritDoc}
*/
public Entry nextMemberEntry()
throws MembershipException
{
if (! hasMoreMembers())
{
return null;
}
{
close();
return null;
}
{
}
else if (result instanceof MembershipException)
{
if (! me.continueIterating())
{
close();
}
throw me;
}
// We should never get here.
close();
return null;
}
/**
* {@inheritDoc}
*/
public void close()
{
searchesCompleted = true;
resultQueue.clear();
}
}