/*
* 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 2008-2009 Sun Microsystems, Inc.
*/
package org.opends.server.extensions;
import org.opends.messages.Message;
import java.util.LinkedHashSet;
import org.opends.server.api.DirectoryThread;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchListener;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DN;
import org.opends.server.types.LDAPURL;
import org.opends.server.types.MembershipException;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchFilter;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.types.SearchScope;
import static org.opends.messages.ExtensionMessages.*;
import org.opends.server.loggers.ErrorLogger;
/**
* This class implements a Directory Server thread that will be used to perform
* a background search to retrieve all of the members of a dynamic group.
* <BR><BR>
*/
public class DynamicGroupSearchThread
// FIXME -- Would it be better to implement this class using an Executor
// rather than always creating a custom thread?
extends DirectoryThread
implements InternalSearchListener
{
// The set of base DNs for the search requests.
private final DN[] baseDNs;
// The member list with which this search thread is associated.
private final DynamicGroupMemberList memberList;
// A counter used to keep track of which search is currently in progress.
private int searchCounter;
// The set of member URLs for determining whether entries match the criteria.
private final LDAPURL[][] memberURLs;
// The set of search filters for the search requests.
private final SearchFilter[] searchFilters;
/**
* Creates a new dynamic group search thread that is associated with the
* provided member list and that will perform the search using the provided
* information.
*
* @param memberList The dynamic group member list with which this thread is
* associated.
* @param baseDNs The set of base DNs to use for the search requests.
* @param filters The set of search filters to use for the search
* requests.
* @param memberURLs The set of member URLs to use when determining if
* entries match the necessary group criteria.
*/
public DynamicGroupSearchThread(DynamicGroupMemberList memberList,
DN[] baseDNs, SearchFilter[] filters,
LDAPURL[][] memberURLs)
{
super("Dynamic Group Search Thread " + memberList.getDynamicGroupDN());
this.memberList = memberList;
this.baseDNs = baseDNs;
this.searchFilters = filters;
this.memberURLs = memberURLs;
searchCounter = 0;
}
/**
* Performs the set of searches and provides the results to the associated
* member list.
*/
public void run()
{
InternalClientConnection conn =
InternalClientConnection.getRootConnection();
LinkedHashSet<String> attributes = new LinkedHashSet<String>(0);
//Include all the user attributes along with the ismemberof.
attributes.add("*");
attributes.add("ismemberof");
for (searchCounter = 0; searchCounter < baseDNs.length; searchCounter++)
{
InternalSearchOperation searchOperation =
conn.processSearch(baseDNs[searchCounter], SearchScope.WHOLE_SUBTREE,
DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0,
false, searchFilters[searchCounter], attributes,
this);
ResultCode resultCode = searchOperation.getResultCode();
if (resultCode != ResultCode.SUCCESS)
{
if (resultCode == ResultCode.NO_SUCH_OBJECT)
{
Message message = WARN_DYNAMICGROUP_NONEXISTENT_BASE_DN.
get(String.valueOf(baseDNs[searchCounter]),
String.valueOf(memberList.getDynamicGroupDN()));
ErrorLogger.logError(message);
continue;
}
else
{
Message message =
ERR_DYNAMICGROUP_INTERNAL_SEARCH_FAILED.get(
String.valueOf(baseDNs[searchCounter]),
String.valueOf(searchFilters[searchCounter]),
String.valueOf(memberList.getDynamicGroupDN()),
String.valueOf(resultCode),
String.valueOf(searchOperation.getErrorMessage()));
if (! memberList.addResult(
new MembershipException(message, true)))
{
memberList.setSearchesCompleted();
return;
}
}
}
}
memberList.setSearchesCompleted();
}
/**
* {@inheritDoc}
*/
public void handleInternalSearchEntry(InternalSearchOperation searchOperation,
SearchResultEntry searchEntry)
throws DirectoryException
{
for (LDAPURL url : memberURLs[searchCounter])
{
if (url.matchesEntry(searchEntry))
{
if (! memberList.addResult(searchEntry))
{
Message message = ERR_DYNAMICGROUP_CANNOT_RETURN_ENTRY.
get(String.valueOf(searchEntry.getDN()),
String.valueOf(memberList.getDynamicGroupDN()));
throw new DirectoryException(
DirectoryServer.getServerErrorResultCode(), message);
}
return;
}
}
}
/**
* {@inheritDoc}
*/
public void handleInternalSearchReference(
InternalSearchOperation searchOperation,
SearchResultReference searchReference)
{
// No implementation required.
}
}