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