/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.jobs; import java.util.ArrayList; import java.util.Date; import com.unboundid.ldap.sdk.Entry; import com.unboundid.ldap.sdk.Filter; import com.unboundid.ldap.sdk.LDAPConnection; import com.unboundid.ldap.sdk.LDAPException; import com.unboundid.ldap.sdk.LDAPSearchException; import com.unboundid.ldap.sdk.SearchRequest; import com.unboundid.ldap.sdk.SearchResult; import com.unboundid.ldap.sdk.SearchScope; import com.unboundid.util.FixedRateBarrier; import com.unboundid.util.ssl.SSLUtil; import com.unboundid.util.ssl.TrustAllTrustManager; import com.slamd.job.JobClass; import com.slamd.job.UnableToRunException; import com.slamd.parameter.BooleanParameter; import com.slamd.parameter.IntegerParameter; import com.slamd.parameter.InvalidValueException; import com.slamd.parameter.Parameter; import com.slamd.parameter.ParameterList; import com.slamd.parameter.PasswordParameter; import com.slamd.parameter.PlaceholderParameter; import com.slamd.parameter.StringParameter; import com.slamd.stat.AccumulatingTracker; import com.slamd.stat.IncrementalTracker; import com.slamd.stat.IntegerValueTracker; import com.slamd.stat.RealTimeStatReporter; import com.slamd.stat.StatTracker; import com.slamd.stat.TimeTracker; /** * This class implements a SLAMD job class that is intended for use in priming * an LDAP directory server. It is very similar to the SearchRate job, but it * is designed specifically for priming, which reads all or a significant part * of the database. Unfortunately, it is necessary to specify the number of * clients to use twice (once for the scheduling info and once as a job * parameter) because otherwise each client does not have any knowledge of the * total number of clients. Note that this job expects the directory entries to * have a sequentially-incrementing counter as a value for one of the attributes * in it (it does not have to be the RDN attribute, but it should be indexed), * so it is unfortunately only feasible to use for contrived data sets. * * * @author Neil A. Wilson */ public class LDAPPrimeJobClass extends JobClass { /** * The display name for the stat tracker that will be used to track the time * required to run each search. */ public static final String STAT_TRACKER_SEARCH_TIME = "Search Time (ms)"; /** * The display name for the stat tracker that will be used to track the number * of entries returned from each search. */ public static final String STAT_TRACKER_ENTRY_COUNT = "Entries Returned"; /** * The display name for the stat tracker that will be used to track the number * of successful searches. */ public static final String STAT_TRACKER_SEARCHES_COMPLETED = "Searches Completed"; /** * The display name for the stat tracker that will be used to accumulate the * total number of successful searches. */ public static final String STAT_TRACKER_TOTAL_SEARCHES_COMPLETED = "Total Searches Completed"; /** * The display name for the stat tracker that will be used to track the number * of exceptions caught. */ public static final String STAT_TRACKER_EXCEPTIONS_CAUGHT = "Exceptions Caught"; // The parameter that indicates whether the client should trust any SSL cert. private BooleanParameter blindTrustParameter = new BooleanParameter("blind_trust", "Blindly Trust Any Certificate", "Indicates whether the client should blindly trust " + "any certificate presented by the server, or " + "whether the key and trust stores should be used.", true); // The parameter that indicates whether the connection should use SSL or not private BooleanParameter useSSLParameter = new BooleanParameter("usessl", "Use SSL", "Indicates whether to use SSL to encrypt the " + "communication with the directory server", false); // The parameter that indicates the number of clients to use for the job. private IntegerParameter clientsParameter = new IntegerParameter("num_clients", "Number of Clients", "The number of clients over which the priming " + "should be distributed", true, 0, true, 1, false, 0); // The parameter that specifies the maximum request rate. private IntegerParameter maxRateParameter = new IntegerParameter("maxRate", "Max Search Rate (Searches/Second/Client)", "Specifies the maximum search rate (in searches per second per " + "client) to attempt to maintain. If multiple clients are used, " + "then each client will attempt to maintain this rate. A value " + "less than or equal to zero indicates that the client should " + "attempt to perform searches as quickly as possible.", true, -1); // The parameter that indicates the port number for the directory server private IntegerParameter portParameter = new IntegerParameter("ldapport", "Directory Server Port", "The port number for the LDAP directory server", true, 389, true, 1, true, 65535); // The parameter that specifies the starting value for the attribute. private IntegerParameter rangeStartParameter = new IntegerParameter("rangestart", "Value Range Start", "The value that should be used as the start of " + "the range when priming the job.", true, 0, false, 0, false, 0); // The parameter that specifies the ending value for the attribute. private IntegerParameter rangeStopParameter = new IntegerParameter("rangestop", "Value Range End", "The value that should be used as the end of " + "the range when priming the job.", true, 0, false, 0, false, 0); // The parameter that specifies the interval over which to enforce the maximum // request rate. private IntegerParameter rateLimitDurationParameter = new IntegerParameter( "maxRateDuration", "Max Rate Enforcement Interval (Seconds)", "Specifies the duration in seconds of the interval over which to " + "attempt to maintain the configured maximum rate. A value of " + "zero indicates that it should be equal to the statistics " + "collection interval. Large values may allow more variation but " + "may be more accurate over time. Small values can better " + "ensure that the rate doesn't exceed the requested level but may " + "be less able to achieve the desired rate.", true, 0, true,0, false, 0); // The parameter that indicates the maximum length of time to wait for results // to a search. private IntegerParameter timeLimitParameter = new IntegerParameter("timelimit", "Search Time Limit", "The maximum length of time to wait for the " + "result of a search operation (0 to wait forever)", true, 0, true, 0, false, 0); // The placeholder parameter used as a spacer in the admin interface. private PlaceholderParameter placeholder = new PlaceholderParameter(); // The parameter that indicates the search base private StringParameter searchBaseParameter = new StringParameter("searchbase", "Search Base", "The DN of the entry to use as the search base", false, ""); // The parameter that specifies the attribute name. private StringParameter attributeNameParameter = new StringParameter("attrname", "Attribute Name", "The name of the LDAP attribute that contains the " + "sequentially-incrementing value used to prime " + "the directory", true, ""); // The parameter that specifies the string to be prepended to the numeric // portion of the attribute value. private StringParameter valuePrefixParameter = new StringParameter("valueprefix", "Attribute Value Prefix", "The static text that should be prepended to the " + "numeric portion of the attribute value for use " + "in the priming searches.", false, ""); // The parameter that specifies the string to be appended to the numeric // portion of the attribute value. private StringParameter valueSuffixParameter = new StringParameter("valuesuffix", "Attribute Value Suffix", "The static text that should be appended to the " + "numeric portion of the attribute value for use " + "in the priming searches.", false, ""); // The parameter that indicates the DN to use when binding to the server private StringParameter bindDNParameter = new StringParameter("binddn", "Bind DN", "The DN to use to bind to the server", false, ""); // The parameter that indicates the address of the directory server private StringParameter hostParameter = new StringParameter("ldaphost", "Directory Server Host", "The DNS hostname or IP address of the LDAP " + "directory server", true, ""); // The parameter that specifies the location of the SSL key store private StringParameter keyStoreParameter = new StringParameter("sslkeystore", "SSL Key Store", "The path to the JSSE key store to use for an " + "SSL-based connection", false, ""); // The parameter that specifies the location of the SSL trust store private StringParameter trustStoreParameter = new StringParameter("ssltruststore", "SSL Trust Store", "The path to the JSSE trust store to use for an " + "SSL-based connection", false, ""); // The parameter that indicates the bind password private PasswordParameter bindPWParameter = new PasswordParameter("bindpw", "Bind Password", "The password for the bind DN", false, ""); // The parameter that specifies the password for the SSL key store private PasswordParameter keyPWParameter = new PasswordParameter("sslkeypw", "SSL Key Store Password", "The password for the JSSE key store", false, ""); // The parameter that specifies the password for the SSL key store private PasswordParameter trustPWParameter = new PasswordParameter("ssltrustpw", "SSL Trust Store Password", "The password for the JSSE trust store", false, ""); // Instance variables that correspond to the parameter values private static boolean useSSL; private static int ldapPort; private static int numClients; private static int rangeStart; private static int rangeStop; private static int timeLimit; private static String attributeName; private static String searchBase; private static String bindDN; private static String bindPassword; private static String ldapHost; private static String valuePrefix; private static String valueSuffix; // The range that will be used for this client. private static int clientMax; private static int clientMin; // The rate limiter for this job. private static FixedRateBarrier rateLimiter; // The range that will be used for this thread. private int threadMax; private int threadMin; // The LDAP connection that will be used to issue the searches. private LDAPConnection conn; // Variables used for status counters private AccumulatingTracker totalSearches; private IncrementalTracker exceptionsCaught; private IncrementalTracker successfulSearches; private IntegerValueTracker entryCount; private TimeTracker searchTime; /** * The default constructor used to create a new instance of the search thread. * The only thing it should do is to invoke the superclass constructor. All * other initialization should be performed in the <CODE>initialize</CODE> * method. */ public LDAPPrimeJobClass() { super(); } /** * {@inheritDoc} */ @Override() public String getJobName() { return "LDAP Prime"; } /** * {@inheritDoc} */ @Override() public String getShortDescription() { return "Prime directory server caches using LDAP search operations"; } /** * {@inheritDoc} */ @Override() public String[] getLongDescription() { return new String[] { "This job can be used to attempt to prime the caches of an LDAP " + "directory server by performing search operations. It is expected " + "that the directory server will have a data set containing an indexed " + "attribute whose value contains a sequentially-incrementing number." }; } /** * {@inheritDoc} */ @Override() public String getJobCategoryName() { return "LDAP"; } /** * {@inheritDoc} */ @Override() public ParameterList getParameterStubs() { Parameter[] parameters = new Parameter[] { placeholder, hostParameter, portParameter, bindDNParameter, bindPWParameter, placeholder, searchBaseParameter, attributeNameParameter, rangeStartParameter, rangeStopParameter, valuePrefixParameter, valueSuffixParameter, timeLimitParameter, maxRateParameter, placeholder, useSSLParameter, blindTrustParameter, keyStoreParameter, keyPWParameter, trustStoreParameter, trustPWParameter }; return new ParameterList(parameters); } /** * {@inheritDoc} */ @Override() public ParameterList getClientSideParameterStubs() { Parameter[] parameters = new Parameter[] { placeholder, hostParameter, portParameter, bindDNParameter, bindPWParameter, placeholder, searchBaseParameter, attributeNameParameter, rangeStartParameter, rangeStopParameter, valuePrefixParameter, valueSuffixParameter, timeLimitParameter, maxRateParameter, rateLimitDurationParameter, placeholder, useSSLParameter, blindTrustParameter, keyStoreParameter, keyPWParameter, trustStoreParameter, trustPWParameter, clientsParameter }; return new ParameterList(parameters); } /** * {@inheritDoc} */ @Override() public StatTracker[] getStatTrackerStubs(String clientID, String threadID, int collectionInterval) { return new StatTracker[] { new IncrementalTracker(clientID, threadID, STAT_TRACKER_SEARCHES_COMPLETED, collectionInterval), new IncrementalTracker(clientID, threadID, STAT_TRACKER_EXCEPTIONS_CAUGHT, collectionInterval), new IntegerValueTracker(clientID, threadID, STAT_TRACKER_ENTRY_COUNT, collectionInterval), new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME, collectionInterval) }; } /** * {@inheritDoc} */ @Override() public StatTracker[] getStatTrackers() { return new StatTracker[] { successfulSearches, totalSearches, exceptionsCaught, entryCount, searchTime }; } /** * {@inheritDoc} */ @Override() public void validateJobInfo(int numClients, int threadsPerClient, int threadStartupDelay, Date startTime, Date stopTime, int duration, int collectionInterval, ParameterList parameters) throws InvalidValueException { // This is sneaky. We're going to pass the number of clients to the job as // a job parameter. Otherwise, the job would have no idea how many clients // there are, and therefore would have no idea how to break up the work for // each client. IntegerParameter clientsParameter = new IntegerParameter("num_clients", numClients); parameters.addParameter(clientsParameter); } /** * {@inheritDoc} */ @Override() public boolean providesParameterTest() { return true; } /** * {@inheritDoc} */ @Override() public boolean testJobParameters(ParameterList parameters, ArrayList<String> outputMessages) { // Get all the parameters that we might need to perform the test. StringParameter hostParam = parameters.getStringParameter(hostParameter.getName()); if ((hostParam == null) || (! hostParam.hasValue())) { outputMessages.add("ERROR: No directory server address was provided."); return false; } String host = hostParam.getStringValue(); IntegerParameter portParam = parameters.getIntegerParameter(portParameter.getName()); if ((portParam == null) || (! hostParam.hasValue())) { outputMessages.add("ERROR: No directory server port was provided."); return false; } int port = portParam.getIntValue(); boolean useSSL = false; BooleanParameter useSSLParam = parameters.getBooleanParameter(useSSLParameter.getName()); if (useSSLParam != null) { useSSL = useSSLParam.getBooleanValue(); } String bindDN = ""; StringParameter bindDNParam = parameters.getStringParameter(bindDNParameter.getName()); if ((bindDNParam != null) && bindDNParam.hasValue()) { bindDN = bindDNParam.getStringValue(); } String bindPassword = ""; PasswordParameter bindPWParam = parameters.getPasswordParameter(bindPWParameter.getName()); if ((bindPWParam != null) && bindPWParam.hasValue()) { bindPassword = bindPWParam.getStringValue(); } StringParameter baseDNParam = parameters.getStringParameter(searchBaseParameter.getName()); if ((baseDNParam == null) || (! baseDNParam.hasValue())) { outputMessages.add("ERROR: No base DN was provided."); return false; } String baseDN = baseDNParam.getStringValue(); // Create the LDAPConnection object that we will use to communicate with the // directory server. LDAPConnection conn; if (useSSL) { try { SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); conn = new LDAPConnection(sslUtil.createSSLSocketFactory()); } catch (Exception e) { outputMessages.add("ERROR: Unable to instantiate the socket " + "factory for use in creating the SSL connection: " + stackTraceToString(e)); return false; } } else { conn = new LDAPConnection(); } // Attempt to establish a connection to the directory server. try { outputMessages.add("Attempting to establish a connection to " + host + ':' + port + "...."); conn.connect(host, port, 10000); outputMessages.add("Connected successfully."); outputMessages.add(""); } catch (Exception e) { outputMessages.add("ERROR: Unable to connect to the directory " + "server: " + stackTraceToString(e)); return false; } // Attempt to bind to the directory server using the bind DN and password. try { if ((bindDN != null) && (bindDN.length() > 0) && (bindPassword != null) && (bindPassword.length() > 0)) { outputMessages.add("Attempting to perform an LDAPv3 bind to the " + "directory server with a DN of '" + bindDN + "'...."); conn.bind(bindDN, bindPassword); outputMessages.add("Bound successfully."); outputMessages.add(""); } } catch (Exception e) { try { conn.close(); } catch (Exception e2) {} outputMessages.add("ERROR: Unable to bind to the directory server: " + stackTraceToString(e)); return false; } // Make sure that the entry specified as the base DN exists. try { outputMessages.add("Checking to make sure that the base DN entry '" + baseDN + "' exists in the directory...."); Entry baseDNEntry = conn.getEntry(baseDN, "1.1"); if (baseDNEntry == null) { try { conn.close(); } catch (Exception e2) {} outputMessages.add("ERROR: Unable to retrieve the base DN entry."); return false; } else { outputMessages.add("Successfully read the base DN entry."); outputMessages.add(""); } } catch (Exception e) { try { conn.close(); } catch (Exception e2) {} outputMessages.add("ERROR: Unable to retrieve the base DN entry: " + stackTraceToString(e)); return false; } // At this point, all tests have passed. Close the connection and return // true. try { conn.close(); } catch (Exception e) {} outputMessages.add("All tests completed successfully."); return true; } /** * {@inheritDoc} */ @Override() public void initializeClient(String clientID, ParameterList parameters) throws UnableToRunException { // Get the address of the target directory server ldapHost = null; hostParameter = parameters.getStringParameter(hostParameter.getName()); if (hostParameter != null) { ldapHost = hostParameter.getStringValue(); } // Get the port for the target directory server ldapPort = 389; portParameter = parameters.getIntegerParameter(portParameter.getName()); if (portParameter != null) { ldapPort = portParameter.getIntValue(); } // Get the bind DN for the target directory server bindDN = ""; bindDNParameter = parameters.getStringParameter(bindDNParameter.getName()); if (bindDNParameter != null) { bindDN = bindDNParameter.getStringValue(); } // Get the bind password for the target directory server bindPassword = ""; bindPWParameter = parameters.getPasswordParameter(bindPWParameter.getName()); if (bindPWParameter != null) { bindPassword = bindPWParameter.getStringValue(); } // Get the search base searchBase = ""; searchBaseParameter = parameters.getStringParameter(searchBaseParameter.getName()); if (searchBaseParameter != null) { searchBase = searchBaseParameter.getStringValue(); } // Get the attribute name attributeName = null; attributeNameParameter = parameters.getStringParameter(attributeNameParameter.getName()); if (attributeNameParameter != null) { attributeName = attributeNameParameter.getStringValue(); } // Get the range start value. rangeStart = 0; rangeStartParameter = parameters.getIntegerParameter(rangeStartParameter.getName()); if (rangeStartParameter != null) { rangeStart = rangeStartParameter.getIntValue(); } // Get the range end value. rangeStop = Integer.MAX_VALUE; rangeStopParameter = parameters.getIntegerParameter(rangeStopParameter.getName()); if (rangeStopParameter != null) { rangeStop = rangeStopParameter.getIntValue(); } // Get the value prefix. valuePrefix = ""; valuePrefixParameter = parameters.getStringParameter(valuePrefixParameter.getName()); if ((valuePrefixParameter != null) && valuePrefixParameter.hasValue()) { valuePrefix = valuePrefixParameter.getStringValue(); } // Get the value suffix. valueSuffix = ""; valueSuffixParameter = parameters.getStringParameter(valueSuffixParameter.getName()); if ((valueSuffixParameter != null) && valueSuffixParameter.hasValue()) { valueSuffix = valueSuffixParameter.getStringValue(); } // Get the time limit per search. timeLimit = 0; timeLimitParameter = parameters.getIntegerParameter(timeLimitParameter.getName()); if (timeLimitParameter != null) { timeLimit = timeLimitParameter.getIntValue(); } // Get the maximum search rate. rateLimiter = null; maxRateParameter = parameters.getIntegerParameter(maxRateParameter.getName()); if ((maxRateParameter != null) && maxRateParameter.hasValue()) { int maxRate = maxRateParameter.getIntValue(); if (maxRate > 0) { int rateIntervalSeconds = 0; rateLimitDurationParameter = parameters.getIntegerParameter( rateLimitDurationParameter.getName()); if ((rateLimitDurationParameter != null) && rateLimitDurationParameter.hasValue()) { rateIntervalSeconds = rateLimitDurationParameter.getIntValue(); } if (rateIntervalSeconds <= 0) { rateIntervalSeconds = getClientSideJob().getCollectionInterval(); } rateLimiter = new FixedRateBarrier(rateIntervalSeconds * 1000L, maxRate * rateIntervalSeconds); } } // Get the flag indicating whether we should use SSL or not. If so, then // we'll blindly trust any certificate presented by the server and will // ignore any key store and trust store options that might have been // provided. useSSL = false; useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName()); if (useSSLParameter != null) { useSSL = useSSLParameter.getBooleanValue(); } // Get the total number of clients. numClients = 0; clientsParameter = parameters.getIntegerParameter(clientsParameter.getName()); if (clientsParameter != null) { numClients = clientsParameter.getIntValue(); } // Calculate the range of values that will be used by this client. int totalSpan = rangeStop - rangeStart + 1; int spanPerClient = totalSpan / numClients; if ((totalSpan % numClients) != 0) { spanPerClient++; } int clientNumber = getClientNumber(); if (clientNumber >= numClients) { throw new UnableToRunException("Detected that this client is client " + "number " + clientNumber + ", but the reported number of clients " + "was " + numClients + " -- skipping this client"); } else if (clientNumber == (numClients - 1)) { clientMin = (clientNumber * spanPerClient) + rangeStart; clientMax = rangeStop; } else { clientMin = (clientNumber * spanPerClient) + rangeStart; clientMax = clientMin + spanPerClient - 1; } } /** * {@inheritDoc} */ @Override() public void initializeThread(String clientID, String threadID, int collectionInterval, ParameterList parameters) throws UnableToRunException { // Set up the status counters entryCount = new IntegerValueTracker(clientID, threadID, STAT_TRACKER_ENTRY_COUNT, collectionInterval); exceptionsCaught = new IncrementalTracker(clientID, threadID, STAT_TRACKER_EXCEPTIONS_CAUGHT, collectionInterval); searchTime = new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME, collectionInterval); successfulSearches = new IncrementalTracker(clientID, threadID, STAT_TRACKER_SEARCHES_COMPLETED, collectionInterval); totalSearches = new AccumulatingTracker(clientID, threadID, STAT_TRACKER_TOTAL_SEARCHES_COMPLETED, collectionInterval); // Enable real-time reporting of the data for these stat trackers. RealTimeStatReporter statReporter = getStatReporter(); if (statReporter != null) { String jobID = getJobID(); successfulSearches.enableRealTimeStats(statReporter, jobID); totalSearches.enableRealTimeStats(statReporter, jobID); exceptionsCaught.enableRealTimeStats(statReporter, jobID); entryCount.enableRealTimeStats(statReporter, jobID); searchTime.enableRealTimeStats(statReporter, jobID); } // Figure out the span to use for this particular thread. int numThreads = getClientSideJob().getThreadsPerClient(); int clientSpan = clientMax - clientMin + 1; int spanPerThread = clientSpan / numThreads; if ((clientSpan % numThreads) != 0) { spanPerThread++; } int threadNumber = getThreadNumber(); if (threadNumber == (numThreads - 1)) { threadMin = (threadNumber * spanPerThread) + clientMin; threadMax = clientMax; } else { threadMin = (threadNumber * spanPerThread) + clientMin; threadMax = threadMin + spanPerThread - 1; } // If the connection is to use SSL, then establish a preliminary connection // now. The first connection can take a significant amount of time to // establish, and we want to get it out of the way early before the timer // starts (if a duration is specified). Don't worry about any exceptions // that may get thrown here because there's no easy way to report them back // but they will be repeated and handled when the job starts running anyway, // so no big deal. if (useSSL) { try { SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); conn = new LDAPConnection(sslUtil.createSSLSocketFactory()); conn.connect(ldapHost, ldapPort, 10000); if ((bindDN != null) && (bindDN.length() > 0) && (bindPassword != null) && (bindPassword.length() > 0)) { conn.bind(bindDN, bindPassword); } conn.close(); } catch (Exception e) {} } } /** * {@inheritDoc} */ @Override() public void runJob() { // Establish the connection to the directory server. if (useSSL) { try { SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); conn = new LDAPConnection(sslUtil.createSSLSocketFactory()); } catch (Exception e) { logMessage(e.getMessage()); indicateStoppedDueToError(); return; } } else { conn = new LDAPConnection(); } try { conn.connect(ldapHost, ldapPort, 10000); } catch (LDAPException le) { logMessage("Unable to connect to directory server " + ldapHost + ':' + ldapPort + ": " + le); indicateCompletedWithErrors(); return; } // Create the search request that will be used by this thread. SearchRequest searchRequest = new SearchRequest(searchBase, SearchScope.SUB, Filter.createEqualityFilter(attributeName, "x")); searchRequest.setTimeLimitSeconds(timeLimit); searchRequest.setResponseTimeoutMillis(1000L * timeLimit); // Tell the stat trackers that they should start tracking now successfulSearches.startTracker(); totalSearches.startTracker(); exceptionsCaught.startTracker(); entryCount.startTracker(); searchTime.startTracker(); // Create a loop that will run until it needs to stop for (int i=threadMin; ((! shouldStop()) && (i <= threadMax)); i++) { if (rateLimiter != null) { if (rateLimiter.await()) { continue; } } // Create a flag that will be used to determine if the search was // successful or not boolean successfulSearch = false; // Create a counter that will be used to record the number of matching // entries int matchingEntries = 0; // Perform the search and iterate through all matching entries searchTime.startTimer(); try { searchRequest.setFilter(Filter.createEqualityFilter(attributeName, valuePrefix + i + valueSuffix)); SearchResult result = conn.search(searchRequest); successfulSearch = true; matchingEntries = result.getEntryCount(); } catch (LDAPSearchException e) { exceptionsCaught.increment(); matchingEntries = e.getEntryCount(); indicateCompletedWithErrors(); } catch (Exception e) { exceptionsCaught.increment(); indicateCompletedWithErrors(); } // Record the current time as the end of the search searchTime.stopTimer(); // Update the appropriate status counters if (successfulSearch) { entryCount.addValue(matchingEntries); successfulSearches.increment(); totalSearches.increment(); } } // If the connection is still established, then close it conn.close(); // Tell the stat trackers that they should stop tracking successfulSearches.stopTracker(); totalSearches.stopTracker(); exceptionsCaught.stopTracker(); entryCount.stopTracker(); searchTime.stopTracker(); } /** * {@inheritDoc} */ @Override() public void destroyThread() { if (conn != null) { try { conn.close(); } catch (Exception e) {} conn = null; } } }