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