001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2008-2009 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import org.forgerock.i18n.LocalizableMessage; 020import org.forgerock.i18n.slf4j.LocalizedLogger; 021import org.forgerock.opendj.ldap.ResultCode; 022import org.forgerock.opendj.ldap.SearchScope; 023import org.opends.server.api.DirectoryThread; 024import org.opends.server.core.DirectoryServer; 025import org.opends.server.protocols.internal.InternalClientConnection; 026import org.opends.server.protocols.internal.InternalSearchListener; 027import org.opends.server.protocols.internal.InternalSearchOperation; 028import org.opends.server.protocols.internal.SearchRequest; 029import static org.opends.server.protocols.internal.Requests.*; 030import org.forgerock.opendj.ldap.DN; 031import org.opends.server.types.DirectoryException; 032import org.opends.server.types.LDAPURL; 033import org.opends.server.types.MembershipException; 034import org.opends.server.types.SearchFilter; 035import org.opends.server.types.SearchResultEntry; 036import org.opends.server.types.SearchResultReference; 037 038import static org.opends.messages.ExtensionMessages.*; 039import static org.opends.server.protocols.internal.InternalClientConnection.*; 040 041/** 042 * This class implements a Directory Server thread that will be used to perform 043 * a background search to retrieve all of the members of a dynamic group. 044 * <BR><BR> 045 */ 046public class DynamicGroupSearchThread 047// FIXME -- Would it be better to implement this class using an Executor 048// rather than always creating a custom thread? 049 extends DirectoryThread 050 implements InternalSearchListener 051{ 052 053 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 054 055 /** The set of base DNs for the search requests. */ 056 private final DN[] baseDNs; 057 058 /** The member list with which this search thread is associated. */ 059 private final DynamicGroupMemberList memberList; 060 061 /** A counter used to keep track of which search is currently in progress. */ 062 private int searchCounter; 063 064 /** The set of member URLs for determining whether entries match the criteria. */ 065 private final LDAPURL[][] memberURLs; 066 067 /** The set of search filters for the search requests. */ 068 private final SearchFilter[] searchFilters; 069 070 071 072 /** 073 * Creates a new dynamic group search thread that is associated with the 074 * provided member list and that will perform the search using the provided 075 * information. 076 * 077 * @param memberList The dynamic group member list with which this thread is 078 * associated. 079 * @param baseDNs The set of base DNs to use for the search requests. 080 * @param filters The set of search filters to use for the search 081 * requests. 082 * @param memberURLs The set of member URLs to use when determining if 083 * entries match the necessary group criteria. 084 */ 085 public DynamicGroupSearchThread(DynamicGroupMemberList memberList, 086 DN[] baseDNs, SearchFilter[] filters, 087 LDAPURL[][] memberURLs) 088 { 089 super("Dynamic Group Search Thread " + memberList.getDynamicGroupDN()); 090 091 this.memberList = memberList; 092 this.baseDNs = baseDNs; 093 this.searchFilters = filters; 094 this.memberURLs = memberURLs; 095 096 searchCounter = 0; 097 } 098 099 100 101 /** 102 * Performs the set of searches and provides the results to the associated 103 * member list. 104 */ 105 @Override 106 public void run() 107 { 108 InternalClientConnection conn = getRootConnection(); 109 for (searchCounter = 0; searchCounter < baseDNs.length; searchCounter++) 110 { 111 DN baseDN = baseDNs[searchCounter]; 112 SearchFilter filter = searchFilters[searchCounter]; 113 // Include all the user attributes along with the ismemberof. 114 final SearchRequest request = newSearchRequest(baseDN, SearchScope.WHOLE_SUBTREE, filter) 115 .addAttribute("*", "ismemberof"); 116 InternalSearchOperation searchOperation = conn.processSearch(request, this); 117 118 ResultCode resultCode = searchOperation.getResultCode(); 119 if (resultCode != ResultCode.SUCCESS) 120 { 121 if (resultCode == ResultCode.NO_SUCH_OBJECT) 122 { 123 logger.warn(WARN_DYNAMICGROUP_NONEXISTENT_BASE_DN, baseDN, 124 memberList.getDynamicGroupDN()); 125 continue; 126 } 127 else 128 { 129 LocalizableMessage message = 130 ERR_DYNAMICGROUP_INTERNAL_SEARCH_FAILED.get( 131 baseDN, 132 filter, 133 memberList.getDynamicGroupDN(), 134 resultCode, 135 searchOperation.getErrorMessage()); 136 if (! memberList.addResult( 137 new MembershipException(message, true))) 138 { 139 memberList.setSearchesCompleted(); 140 return; 141 } 142 } 143 } 144 } 145 146 memberList.setSearchesCompleted(); 147 } 148 149 150 151 /** {@inheritDoc} */ 152 @Override 153 public void handleInternalSearchEntry(InternalSearchOperation searchOperation, 154 SearchResultEntry searchEntry) 155 throws DirectoryException 156 { 157 for (LDAPURL url : memberURLs[searchCounter]) 158 { 159 if (url.matchesEntry(searchEntry)) 160 { 161 if (! memberList.addResult(searchEntry)) 162 { 163 LocalizableMessage message = ERR_DYNAMICGROUP_CANNOT_RETURN_ENTRY. 164 get(searchEntry.getName(), memberList.getDynamicGroupDN()); 165 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), message); 166 } 167 168 return; 169 } 170 } 171 } 172 173 174 175 /** {@inheritDoc} */ 176 @Override 177 public void handleInternalSearchReference( 178 InternalSearchOperation searchOperation, 179 SearchResultReference searchReference) 180 { 181 // No implementation required. 182 } 183} 184