KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > slamd > example > LDAPLoadJobClass


1 /*
2  * Sun Public License
3  *
4  * The contents of this file are subject to the Sun Public License Version
5  * 1.0 (the "License"). You may not use this file except in compliance with
6  * the License. A copy of the License is available at http://www.sun.com/
7  *
8  * The Original Code is the SLAMD Distributed Load Generation Engine.
9  * The Initial Developer of the Original Code is Neil A. Wilson.
10  * Portions created by Neil A. Wilson are Copyright (C) 2004.
11  * Some preexisting portions Copyright (C) 2002-2004 Sun Microsystems, Inc.
12  * All Rights Reserved.
13  *
14  * Contributor(s): Neil A. Wilson
15  */

16 package com.sun.slamd.example;
17
18
19
20 import java.io.*;
21 import java.security.*;
22 import java.util.*;
23 import netscape.ldap.*;
24 import netscape.ldap.controls.*;
25 import netscape.ldap.factory.*;
26 import com.sun.slamd.job.*;
27 import com.sun.slamd.parameter.*;
28 import com.sun.slamd.stat.*;
29
30
31
32 /**
33  * This class implements a SLAMD job class that has the ability to generate
34  * various kinds of load against an LDAP directory server. It can perform
35  * search, compare, add, delete, modify, and modify RDN operations. The
36  * relative frequencies of each kind of operation may be specified by the user
37  * scheduling the job for execution.
38  *
39  *
40  * @author Neil A. Wilson
41  */

42 public class LDAPLoadJobClass
43        extends JobClass
44        implements LDAPRebind
45 {
46   /**
47    * The set of characters that will make up randomly-generated strings.
48    */

49   public static final char[] ALPHABET =
50        "abcdefghijklmnopqrstuvwxyz".toCharArray();
51
52
53
54   /**
55    * The system property used to specify the location of the JSSE key store.
56    */

57   public static final String JavaDoc SSL_KEY_STORE_PROPERTY =
58        "javax.net.ssl.keyStore";
59
60
61
62   /**
63    * The system property used to specify the password for the JSSE key store.
64    */

65   public static final String JavaDoc SSL_KEY_PASSWORD_PROPERTY =
66        "javax.net.ssl.keyStorePassword";
67
68
69
70   /**
71    * The system property used to specify the location of the JSSE trust store.
72    */

73   public static final String JavaDoc SSL_TRUST_STORE_PROPERTY =
74        "javax.net.ssl.trustStore";
75
76
77
78   /**
79    * The system property used to specify the password for the JSSE trust store.
80    */

81   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
82        "javax.net.ssl.trustStorePassword";
83
84
85
86   /**
87    * The name of the stat tracker that counts the number of attempted adds.
88    */

89   public static final String JavaDoc STAT_TRACKER_ADD_ATTEMPTS = "Add Attempts";
90
91
92
93   /**
94    * The name of the stat tracker that times add operations.
95    */

96   public static final String JavaDoc STAT_TRACKER_ADD_TIME = "Add Time (ms)";
97
98
99
100   /**
101    * The name of the stat tracker that counts the number of attempted compares.
102    */

103   public static final String JavaDoc STAT_TRACKER_COMPARE_ATTEMPTS = "Compare Attempts";
104
105
106
107   /**
108    * The name of the stat tracke that times compare operations.
109    */

110   public static final String JavaDoc STAT_TRACKER_COMPARE_TIME = "Compare Time (ms)";
111
112
113
114   /**
115    * The name of the stat tracker that counts the number of attempted deletes.
116    */

117   public static final String JavaDoc STAT_TRACKER_DELETE_ATTEMPTS = "Delete Attempts";
118
119
120
121   /**
122    * The name of the stat tracker that times delete operations.
123    */

124   public static final String JavaDoc STAT_TRACKER_DELETE_TIME = "Delete Time (ms)";
125
126
127
128   /**
129    * The name of the stat tracker that counts the number of attempted modifies.
130    */

131   public static final String JavaDoc STAT_TRACKER_MODIFY_ATTEMPTS = "Modify Attempts";
132
133
134
135   /**
136    * The name of the stat tracker that times modify operations.
137    */

138   public static final String JavaDoc STAT_TRACKER_MODIFY_TIME = "Modify Time (ms)";
139
140
141
142   /**
143    * The name of the stat tracker that counts the number of attempted modify RDN
144    * operations.
145    */

146   public static final String JavaDoc STAT_TRACKER_MODIFY_RDN_ATTEMPTS =
147        "Modify RDN Attempts";
148
149
150
151   /**
152    * The name of the stat tracker that times modify RDN operations.
153    */

154   public static final String JavaDoc STAT_TRACKER_MODIFY_RDN_TIME =
155        "Modify RDN Time (ms)";
156
157
158
159   /**
160    * The name of the stat tracker that counts the number of attempted
161    * operations.
162    */

163   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS =
164        "Overall Operations Attempted";
165
166
167
168   /**
169    * The name of the stat tracker that categorizes the attempted operations.
170    */

171   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY =
172        "Types of Operations Attempted";
173
174
175
176   /**
177    * The name of the stat tracker that times attempted operations.
178    */

179   public static final String JavaDoc STAT_TRACKER_OPERATION_TIME =
180        "Overall Operation Time";
181
182
183
184   /**
185    * The name of the stat tracker that categorizes the result codes received
186    * from the operations.
187    */

188   public static final String JavaDoc STAT_TRACKER_RESULT_CODES = "Result Codes";
189
190
191
192   /**
193    * The name of the stat tracker that counts the number of attempted searches.
194    */

195   public static final String JavaDoc STAT_TRACKER_SEARCH_ATTEMPTS = "Search Attempts";
196
197
198
199   /**
200    * The name of the stat tracker that times search operations.
201    */

202   public static final String JavaDoc STAT_TRACKER_SEARCH_TIME = "Search Time (ms)";
203
204
205
206   // The parameter that indicates whether the client should trust any SSL cert.
207
BooleanParameter blindTrustParameter =
208     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
209                          "Indicates whether the client should blindly trust " +
210                          "any certificate presented by the server, or " +
211                          "whether the key and trust stores should be used.",
212                          true);
213
214   // The parameter that indicates whether the job should clean up any entries
215
// that may have been added during processing.
216
BooleanParameter cleanUpParameter =
217        new BooleanParameter("cleanup", "Clean Up When Done",
218                             "Indicates whether each client should clean up " +
219                             "any entries that may have been added during " +
220                             "processing that have not yet been removed.", true);
221
222   // The parameter that indicates whether to disconnect after each operation.
223
BooleanParameter disconnectParameter =
224        new BooleanParameter("disconnect", "Always Disconnect",
225                             "Indicates whether to close and re-establish the " +
226                             "connection to the directory server after each " +
227                             "operation.", false);
228
229   // The parameter that indicates whether to follow referrals.
230
BooleanParameter referralsParameter =
231        new BooleanParameter("follow_referrals", "Follow Referrals",
232                             "Indicates whether to follow referrals " +
233                             "encountered while performing operations in the " +
234                             "directory.", false);
235
236   // The parameter that indicates whether to use SSL when communicating with the
237
// directory server.
238
BooleanParameter useSSLParameter =
239        new BooleanParameter("use_ssl", "Use SSL",
240                             "Indicates whether to use SSL when communicating " +
241                             "with the directory server.", false);
242
243   // The parameter that specifies the URL of the entry DN file.
244
FileURLParameter dnFileURLParameter =
245        new FileURLParameter("dn_file_url", "DN File URL",
246                             "Specifies the URL (FILE or HTTP) to the file " +
247                             "that contains the DNs of entries that should " +
248                             "be targeted for LDAP Operations", null, false);
249
250   // The parameter that specifies the URL of the search filter file.
251
FileURLParameter filterFileURLParameter =
252        new FileURLParameter("filter_file_url", "Search Filter File URL",
253                             "Specifies the URL (FILE or HTTP) to the file " +
254                             "that contains a set of filters that may be used " +
255                             "when performing searches.", null, false);
256
257   // The parameter that specifies the frequency for add operations.
258
IntegerParameter addFrequencyParameter =
259     new IntegerParameter("add_frequency", "Add Operation Frequency",
260                          "Specifies the frequency with which adds should be " +
261                          "performed relative to the other types of operations.",
262                          true, 0, true, 0, false, 0);
263
264   // The parameter that specifies the frequency for compare operations.
265
IntegerParameter compareFrequencyParameter =
266        new IntegerParameter("compare_frequency", "Compare Operation Frequency",
267                             "Specifies the frequency with which compares " +
268                             "should be performed relative to the other types " +
269                             "of operations.", true, 0, true, 0, false, 0);
270
271   // The parmeter that specifies the cool-down time in seconds.
272
IntegerParameter coolDownParameter =
273        new IntegerParameter("cool_down", "Cool Down Time",
274                             "The time in seconds that the job should " +
275                             "continue running after ending statistics " +
276                             "collection.", true, 0, true, 0, false, 0);
277
278   // The parameter that specifies the delay between requests.
279
IntegerParameter delayParameter =
280        new IntegerParameter("request_delay", "Time Between Requests (ms)",
281                             "Specifies the length of time in milliseconds " +
282                             "that will pass between requests. Note that " +
283                             "is the time between requests and not the time " +
284                             "between the end of one operation and the " +
285                             "beginning of the next. If any operation takes " +
286                             "longer than this length of time, then there " +
287                             "will be no delay before the start of the next " +
288                             "operation.", false, 0, true, 0, false, 0);
289
290   // The parameter that specifies the frequency for delete operations.
291
IntegerParameter deleteFrequencyParameter =
292        new IntegerParameter("delete_frequency", "Delete Operation Frequency",
293                             "Specifies the frequency with which deletes " +
294                             "should be performed relative to the other types " +
295                             "of operations.", true, 0, true, 0, false, 0);
296
297   // The parameter that specifies the frequency for modify operations.
298
IntegerParameter modifyFrequencyParameter =
299        new IntegerParameter("modify_frequency", "Modify Operation Frequency",
300                             "Specifies the frequency with which modifies " +
301                             "should be performed relative to the other types " +
302                             "of operations.", true, 0, true, 0, false, 0);
303
304   // The parameter that specifies the frequency for modify RDN operations.
305
IntegerParameter modifyRDNFrequencyParameter =
306        new IntegerParameter("modify_rdn_frequency",
307                             "Modify RDN Operation Frequency",
308                             "Specifies the frequency with which modify RDNs " +
309                             "should be performed relative to the other types " +
310                             "of operations.", true, 0, true, 0, false, 0);
311
312   // The parameter that specifies the port number for the directory server.
313
IntegerParameter portParameter =
314        new IntegerParameter("ldap_port", "Directory Server Port",
315                             "Specifies the port number for the directory " +
316                             "server.", true, 389, true, 1, true, 65535);
317
318   // The parameter that specifies the frequency for search operations.
319
IntegerParameter searchFrequencyParameter =
320        new IntegerParameter("Search_frequency", "Search Operation Frequency",
321                             "Specifies the frequency with which compares " +
322                             "should be performed relative to the other types " +
323                             "of operations.", true, 0, true, 0, false, 0);
324
325   // The parameter that specifies the maximum number of entries that should be
326
// returned from a single search operation.
327
IntegerParameter sizeLimitParameter =
328        new IntegerParameter("size_limit", "Search Size Limit",
329                             "Specifies the maximum number of entries that " +
330                             "should be returned from a single search " +
331                             "operation. A size limit of zero indicates that " +
332                             "there is no limit.", false, 0, true, 0, false, 0);
333
334   // The parameter that specifies the maximum length of time in seconds that any
335
// operation will be allowed to take before being abandoned.
336
IntegerParameter timeLimitParameter =
337        new IntegerParameter("time_limit", "Operation Time Limit",
338                             "Specifies the maximum length of time in seconds " +
339                             "will be allowed for any single operation. If " +
340                             "operation takes longer than this length of time " +
341                             "it will be abandoned. A time limit of zero " +
342                             "indicates that there is no time limit.", false, 0,
343                             true, 0, false, 0);
344
345   // The parmeter that specifies the warm-up time in seconds.
346
IntegerParameter warmUpParameter =
347        new IntegerParameter("warm_up", "Warm Up Time",
348                             "The time in seconds that the job should run " +
349                             "before beginning statistics collection.",
350                             true, 0, true, 0, false, 0);
351
352   // The parameter that specifies the password to use when binding to the
353
// directory server.
354
PasswordParameter bindPasswordParameter =
355        new PasswordParameter("bind_pw", "Bind Password",
356                              "Specifies the password to use when binding to " +
357                              "the directory server. If no password is " +
358                              "specified, then the bind will be performed " +
359                              "anonymously.", false, "");
360
361   // The parameter that specifies the password to access the SSL key store.
362
PasswordParameter sslKeyPWParameter =
363        new PasswordParameter("ssl_key_pw", "SSL Key Store Password",
364                              "Specifies the password to use when accessing " +
365                              "the JSSE key store. If SSL is not used, then " +
366                              "this does not need to be specified.", false, "");
367
368   // The parameter that specifies the password to access the SSL trust store.
369
PasswordParameter sslTrustPWParameter =
370        new PasswordParameter("ssl_trust_pw", "SSL Trust Store Password",
371                              "Specifies the password to use when accessing " +
372                              "the JSSE trust store. If SSL is not used, " +
373                              "then this does not need to be specified.", false,
374                              "");
375
376   // A placeholder parameter used to visually group related parameters.
377
PlaceholderParameter placeholder = new PlaceholderParameter();
378
379   // The parameter that specifies the address of the directory server.
380
StringParameter addressParameter =
381        new StringParameter("ldap_host", "Directory Server Address",
382                            "Specifies the address for the directory server.",
383                            true, "");
384
385   // The parameter that specifies the attribute to target for modify and compare
386
// operations.
387
StringParameter attrParameter =
388        new StringParameter("attr", "Attribute to Compare/Modify",
389                            "Specifies the LDAP attribute at which modify and " +
390                            "compare operations will be targeted.", true,
391                            "description");
392
393   // The parameter that specifies the base DN for operations in the directory.
394
StringParameter baseDNParameter =
395        new StringParameter("base_dn", "Directory Base DN",
396                            "Specifies the base DN under which all operations " +
397                            "will be performed in the directory.", true, "");
398
399   // The parameter that specifies the DN to use when binding to the directory.
400
StringParameter bindDNParameter =
401        new StringParameter("bind_dn", "Bind DN",
402                            "Specifies the DN to use when binding to the " +
403                            "directory server for all operations. If no bind " +
404                            "DN is specified, then the bind will be performed " +
405                            "anonymously.", true, "");
406
407   // The parameter that specifies the DN to use when performing operations.
408
StringParameter dnParameter =
409        new StringParameter("entry_dn", "Entry DN",
410                            "Specifies the DN at which all non-search " +
411                            "operations should be targeted. A range of DNs " +
412                            "may be specified by placing the first and last " +
413                            "values in brackets separated by a dash (e.g., " +
414                            "'uid=user.[1-1000],ou=People,dc=example,dc=com')",
415                            false, "");
416
417   // The parameter that specifies the filter to use when performing search
418
// operations.
419
StringParameter filterParameter =
420        new StringParameter("filter", "Search Filter",
421                            "Specifies the search filter to use for all " +
422                            "search operations. A range of filters may be " +
423                            "specified by placing the first and last values " +
424                            "in brackets separated by a dash (e.g., " +
425                            "'(uid=user.[1-1000])')", false, "");
426
427   // The parameter that specifies the DN of the user account whose authority
428
// should be used to perform all operations in the directory.
429
StringParameter proxyAsDNParameter =
430        new StringParameter("proxy_as_dn", "Proxy As DN",
431                            "Specifies the DN of the user whose authority is " +
432                            "to be used when performing operations in the " +
433                            "directory. If this value is specified, then the " +
434                            "proxied authorization control will be used and " +
435                            "the user specified in the bind DN must have the " +
436                            "proxy permission in the directory.", false, "");
437
438   // The parameter that specifies the location of the JSSE key store.
439
StringParameter sslKeyStoreParameter =
440        new StringParameter("ssl_key_store", "SSL Key Store",
441                            "Specifies the location of the JSSE key store to " +
442                            "use with SSL. If SSL is not used, then this " +
443                            "value does not need to be specified.", false, "");
444
445   // The parameter that specifies the location of the JSSE trust store.
446
StringParameter sslTrustStoreParameter =
447        new StringParameter("ssl_trust_store", "SSL Trust Store",
448                            "Specifies the location of the JSSE trust store " +
449                            "to use with SSL. If SSL is not used, then this " +
450                            "value does not need to be specified.", false, "");
451
452   // Static variables used to hold the values of the parameters in each client
453
// (or variables related to the values of those parameters).
454
static boolean alwaysDisconnect;
455   static boolean blindTrust;
456   static boolean cleanUp;
457   static boolean followReferrals;
458   static boolean useDNRange;
459   static boolean useFilterRange;
460   static boolean useSequentialDNs;
461   static boolean useSequentialFilters;
462   static boolean useSSL;
463   static int addFrequency;
464   static int compareFrequency;
465   static int coolDownTime;
466   static int deleteFrequency;
467   static int dnMax;
468   static int dnMin;
469   static int dnSpan;
470   static int filterMax;
471   static int filterMin;
472   static int filterSpan;
473   static int ldapPort;
474   static int modifyFrequency;
475   static int modifyRDNFrequency;
476   static int nextDN;
477   static int nextFilter;
478   static int operationDelay;
479   static int searchFrequency;
480   static int sizeLimit;
481   static int timeLimit;
482   static int totalFrequency;
483   static int warmUpTime;
484   static int[] opWeights;
485   static Random parentRandom;
486   static String JavaDoc baseDN;
487   static String JavaDoc bindDN;
488   static String JavaDoc bindPW;
489   static String JavaDoc dnInitial;
490   static String JavaDoc dnFinal;
491   static String JavaDoc filterInitial;
492   static String JavaDoc filterFinal;
493   static String JavaDoc ldapHost;
494   static String JavaDoc modAttr;
495   static String JavaDoc proxyAsDN;
496   static String JavaDoc sslKeyPW;
497   static String JavaDoc sslKeyStore;
498   static String JavaDoc sslTrustPW;
499   static String JavaDoc sslTrustStore;
500   static String JavaDoc[] entryDNs;
501   static String JavaDoc[] searchFilters;
502
503   // Static variables used to keep track of the DNs of all entries added to the
504
// directory. This list will be used for the entries to delete and to rename.
505
static int dnsToDelete = 0;
506   static LinkedList addedDNs = new LinkedList();
507   static Object JavaDoc addedDNMutex = new Object JavaDoc();
508
509   // Instance variables used as the stat trackers.
510
CategoricalTracker operationTypes;
511   CategoricalTracker resultCodes;
512   IncrementalTracker addCount;
513   IncrementalTracker compareCount;
514   IncrementalTracker deleteCount;
515   IncrementalTracker modifyCount;
516   IncrementalTracker modifyRDNCount;
517   IncrementalTracker operationCount;
518   IncrementalTracker searchCount;
519   TimeTracker addTimer;
520   TimeTracker compareTimer;
521   TimeTracker deleteTimer;
522   TimeTracker modifyTimer;
523   TimeTracker modifyRDNTimer;
524   TimeTracker operationTimer;
525   TimeTracker searchTimer;
526
527   // Other instance variables used in this thread.
528
boolean collectingStats;
529   LDAPConnection conn;
530   LDAPConstraints constraints;
531   LDAPSearchConstraints searchConstraints;
532   Random random;
533
534
535
536
537   /**
538    * Creates a new instance of this job thread. This constructor
539    * does not need to do anything other than invoke the constructor
540    * for the superclass.
541     relative*/

542   public LDAPLoadJobClass()
543   {
544     super();
545   }
546
547
548
549   /**
550    * Returns the user-friendly name that is to be used for this job
551    * class in the administrative interface.
552    *
553    * @return The user-friendly name for this job class.
554    */

555   public String JavaDoc getJobName()
556   {
557     return "LDAP Load Generator";
558   }
559
560
561
562   /**
563    * Returns a description of this job that can be seen in the
564    * administrative interface.
565    *
566    * @return A description of this job class.
567    */

568   public String JavaDoc getJobDescription()
569   {
570     return "This job generates various kinds of load against an LDAP " +
571            "directory server.";
572   }
573
574
575
576   /**
577    * Retrieves the name of the category in which this job class exists. This is
578    * used to help arrange the job classes in the administrative interface.
579    *
580    * @return The name of the category in which this job class exists.
581    */

582   public String JavaDoc getJobCategoryName()
583   {
584     return "LDAP";
585   }
586
587
588
589   /**
590    * Retrieve a parameter list that can be used to determine all of the
591    * customizeable options that are available for this job.
592    *
593    * @return A parameter list that can be used to determine all of the
594    * customizeable options that are available for this job.
595    */

596   public ParameterList getParameterStubs()
597   {
598     Parameter[] params = new Parameter[]
599     {
600       placeholder,
601       addressParameter,
602       portParameter,
603       baseDNParameter,
604       bindDNParameter,
605       bindPasswordParameter,
606       proxyAsDNParameter,
607       placeholder,
608       addFrequencyParameter,
609       compareFrequencyParameter,
610       deleteFrequencyParameter,
611       modifyFrequencyParameter,
612       modifyRDNFrequencyParameter,
613       searchFrequencyParameter,
614       placeholder,
615       dnFileURLParameter,
616       dnParameter,
617       placeholder,
618       filterFileURLParameter,
619       filterParameter,
620       placeholder,
621       attrParameter,
622       placeholder,
623       sizeLimitParameter,
624       timeLimitParameter,
625       warmUpParameter,
626       coolDownParameter,
627       delayParameter,
628       placeholder,
629       useSSLParameter,
630       blindTrustParameter,
631       sslKeyStoreParameter,
632       sslKeyPWParameter,
633       sslTrustStoreParameter,
634       sslTrustPWParameter,
635       placeholder,
636       cleanUpParameter,
637       disconnectParameter,
638       referralsParameter
639     };
640
641     return new ParameterList(params);
642   }
643
644
645
646   /**
647    * Retrieves the set of stat trackers that will be maintained by this job
648    * class. The stat trackers returned by this method do not have to actually
649    * contain any statistics -- the display name and stat tracker class should
650    * be the only information that callers of this method should rely upon. Note
651    * that this list can be different from the list of statistics actually
652    * collected by the job in some cases (e.g., if the job may not return all the
653    * stat trackers it advertises in all cases, or if the job may return stat
654    * trackers that it did not advertise), but it is a possibility that only the
655    * stat trackers returned by this method will be accessible for some features
656    * in the SLAMD server.
657    *
658    * @param clientID The client ID that should be used for the
659    * returned stat trackers.
660    * @param threadID The thread ID that should be used for the
661    * returned stat trackers.
662    * @param collectionInterval The collection interval that should be used for
663    * the returned stat trackers.
664    *
665    * @return The set of stat trackers that will be maintained by this job
666    * class.
667    */

668   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
669                                            int collectionInterval)
670   {
671     return new StatTracker[]
672     {
673       new IncrementalTracker(clientID, threadID,
674                              STAT_TRACKER_OPERATION_ATTEMPTS,
675                              collectionInterval),
676       new TimeTracker(clientID, threadID, STAT_TRACKER_OPERATION_TIME,
677                       collectionInterval),
678       new IncrementalTracker(clientID, threadID, STAT_TRACKER_ADD_ATTEMPTS,
679                              collectionInterval),
680       new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
681                       collectionInterval),
682       new IncrementalTracker(clientID, threadID, STAT_TRACKER_COMPARE_ATTEMPTS,
683                              collectionInterval),
684       new TimeTracker(clientID, threadID, STAT_TRACKER_COMPARE_TIME,
685                       collectionInterval),
686       new IncrementalTracker(clientID, threadID, STAT_TRACKER_DELETE_ATTEMPTS,
687                              collectionInterval),
688       new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
689                       collectionInterval),
690       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MODIFY_ATTEMPTS,
691                              collectionInterval),
692       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_TIME,
693                       collectionInterval),
694       new IncrementalTracker(clientID, threadID,
695                              STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
696                              collectionInterval),
697       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_RDN_TIME,
698                       collectionInterval),
699       new IncrementalTracker(clientID, threadID, STAT_TRACKER_SEARCH_ATTEMPTS,
700                              collectionInterval),
701       new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME,
702                       collectionInterval),
703       new CategoricalTracker(clientID, threadID,
704                              STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
705                              collectionInterval),
706       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
707                              collectionInterval)
708     };
709   }
710
711
712
713   /**
714    * Retrieves the stat trackers that are maintained for this job thread.
715    *
716    * @return The stat trackers that are maintained for this job thread.
717    */

718   public StatTracker[] getStatTrackers()
719   {
720     ArrayList trackerList = new ArrayList();
721
722     // These will always be added, no matter what.
723
trackerList.add(operationCount);
724     trackerList.add(operationTimer);
725     trackerList.add(operationTypes);
726     trackerList.add(resultCodes);
727
728     if (addCount.getTotalCount() > 0)
729     {
730       trackerList.add(addCount);
731       trackerList.add(addTimer);
732     }
733
734     if (compareCount.getTotalCount() > 0)
735     {
736       trackerList.add(compareCount);
737       trackerList.add(compareTimer);
738     }
739
740     if (deleteCount.getTotalCount() > 0)
741     {
742       trackerList.add(deleteCount);
743       trackerList.add(deleteTimer);
744     }
745
746     if (modifyCount.getTotalCount() > 0)
747     {
748       trackerList.add(modifyCount);
749       trackerList.add(modifyTimer);
750     }
751
752     if (modifyRDNCount.getTotalCount() > 0)
753     {
754       trackerList.add(modifyRDNCount);
755       trackerList.add(modifyRDNTimer);
756     }
757
758     if (searchCount.getTotalCount() > 0)
759     {
760       trackerList.add(searchCount);
761       trackerList.add(searchTimer);
762     }
763
764     StatTracker[] trackerArray = new StatTracker[trackerList.size()];
765     trackerList.toArray(trackerArray);
766     return trackerArray;
767   }
768
769
770
771   /**
772    * Provides a means of validating the information used to schedule the job,
773    * including the scheduling information and list of parameters.
774    *
775    * @param numClients The number of clients that should be used to
776    * run the job.
777    * @param threadsPerClient The number of threads that should be created on
778    * each client to run the job.
779    * @param threadStartupDelay The delay in milliseconds that should be used
780    * when starting the client threads.
781    * @param startTime The time that the job should start running.
782    * @param stopTime The time that the job should stop running.
783    * @param duration The maximum length of time in seconds that the
784    * job should be allowed to run.
785    * @param collectionInterval The collection interval that should be used
786    * when gathering statistics for the job.
787    * @param parameters The set of parameters provided to this job that
788    * can be used to customize its behavior.
789    *
790    * @throws InvalidValueException If the provided information is not
791    * appropriate for running this job.
792    */

793   public void validateJobInfo(int numClients, int threadsPerClient,
794                               int threadStartupDelay, Date startTime,
795                               Date stopTime, int duration,
796                               int collectionInterval, ParameterList parameters)
797          throws InvalidValueException
798   {
799     // Make sure that exactly one of the DN parameters was given a value.
800
FileURLParameter dnFileParam =
801          parameters.getFileURLParameter(dnFileURLParameter.getName());
802     StringParameter dnParam =
803          parameters.getStringParameter(dnParameter.getName());
804
805     boolean dnFromFile = ((dnFileParam != null) && dnFileParam.hasValue());
806     boolean dnFromUser = ((dnParam != null) && dnParam.hasValue());
807     if (dnFromFile && dnFromUser)
808     {
809       throw new InvalidValueException("You may not specify both a DN file " +
810                                       "and a single entry DN.");
811     }
812     else if (! (dnFromFile || dnFromUser))
813     {
814       throw new InvalidValueException("You must specify either a DN file URL " +
815                                       "or a single entry DN.");
816     }
817
818
819     // Make sure that exactly one of the filter parameters was given a value.
820
FileURLParameter filterFileParam =
821          parameters.getFileURLParameter(filterFileURLParameter.getName());
822     StringParameter filterParam =
823          parameters.getStringParameter(filterParameter.getName());
824     boolean filterFromFile = ((filterFileParam != null) &&
825                               filterFileParam.hasValue());
826     boolean filterFromUser = ((filterParam != null) && filterParam.hasValue());
827     if (filterFromFile && filterFromUser)
828     {
829       throw new InvalidValueException("You may not specify both a filter " +
830                                       "file and a single search filter.");
831     }
832     else if (! (filterFromFile || filterFromUser))
833     {
834       throw new InvalidValueException("You must specify either a filter file " +
835                                       "or a single search filter.");
836     }
837
838
839     // Make sure that at least one of the frequency parameters was given a
840
// positive value.
841
IntegerParameter addFreqParam =
842          parameters.getIntegerParameter(addFrequencyParameter.getName());
843     if ((addFreqParam != null) && (addFreqParam.getIntValue() > 0))
844     {
845       return;
846     }
847
848     IntegerParameter compareFreqParam =
849          parameters.getIntegerParameter(compareFrequencyParameter.getName());
850     if ((compareFreqParam != null) && (compareFreqParam.getIntValue() > 0))
851     {
852       return;
853     }
854
855     IntegerParameter deleteFreqParam =
856          parameters.getIntegerParameter(deleteFrequencyParameter.getName());
857     if ((deleteFreqParam != null) && (deleteFreqParam.getIntValue() > 0))
858     {
859       return;
860     }
861
862     IntegerParameter modifyFreqParam =
863          parameters.getIntegerParameter(modifyFrequencyParameter.getName());
864     if ((modifyFreqParam != null) && (modifyFreqParam.getIntValue() > 0))
865     {
866       return;
867     }
868
869     IntegerParameter modifyRDNFreqParam =
870          parameters.getIntegerParameter(modifyRDNFrequencyParameter.getName());
871     if ((modifyRDNFreqParam != null) && (modifyRDNFreqParam.getIntValue() > 0))
872     {
873       return;
874     }
875
876     IntegerParameter searchFreqParam =
877          parameters.getIntegerParameter(searchFrequencyParameter.getName());
878     if ((searchFreqParam != null) && (searchFreqParam.getIntValue() > 0))
879     {
880       return;
881     }
882
883     throw new InvalidValueException("At least one operation type must have " +
884                                     "a nonzero frequency.");
885   }
886
887
888
889   /**
890    * Indicates whether this job class implements logic that makes it possible to
891    * test the validity of job parameters before scheduling the job for execution
892    * (e.g., to see if the server is reachable using the information provided).
893    *
894    * @return <CODE>true</CODE> if this job provides a means of testing the job
895    * parameters, or <CODE>false</CODE> if not.
896    */

897   public boolean providesParameterTest()
898   {
899     return true;
900   }
901
902
903
904   /**
905    * Provides a means of testing the provided job parameters to determine
906    * whether they are valid (e.g., to see if the server is reachable) before
907    * scheduling the job for execution. This method will be executed by the
908    * SLAMD server system itself and not by any of the clients.
909    *
910    * @param parameters The job parameters to be tested.
911    * @param outputMessages The lines of output that were generated as part of
912    * the testing process. Each line of output should
913    * be added to this list as a separate string, and
914    * empty strings (but not <CODE>null</CODE> values)
915    * are allowed to provide separation between
916    * different messages. No formatting should be
917    * provided for these messages, however, since they
918    * may be displayed in either an HTML or plain text
919    * interface.
920    *
921    * @return <CODE>true</CODE> if the test completed successfully, or
922    * <CODE>false</CODE> if not. Note that even if the test did not
923    * complete successfully, the user will be presented with a warning
924    * but will still be allowed to schedule the job using the provided
925    * parameters. This is necessary because the parameters may still be
926    * valid even if the server couldn't validate them at the time the
927    * job was scheduled (e.g., if the server wasn't running or could not
928    * be reached by the SLAMD server even though it could be by the
929    * clients).
930    */

931   public boolean testJobParameters(ParameterList parameters,
932                                    ArrayList outputMessages)
933   {
934     // Get all the parameters that we might need to perform the test.
935
StringParameter hostParam =
936          parameters.getStringParameter(addressParameter.getName());
937     if ((hostParam == null) || (! hostParam.hasValue()))
938     {
939       outputMessages.add("ERROR: No directory server address was provided.");
940       return false;
941     }
942     String JavaDoc host = hostParam.getStringValue();
943
944
945     IntegerParameter portParam =
946          parameters.getIntegerParameter(portParameter.getName());
947     if ((portParam == null) || (! hostParam.hasValue()))
948     {
949       outputMessages.add("ERROR: No directory server port was provided.");
950       return false;
951     }
952     int port = portParam.getIntValue();
953
954
955     boolean useSSL = false;
956     BooleanParameter useSSLParam =
957          parameters.getBooleanParameter(useSSLParameter.getName());
958     if (useSSLParam != null)
959     {
960       useSSL = useSSLParam.getBooleanValue();
961     }
962
963
964     boolean blindTrust = true;
965     BooleanParameter blindTrustParam =
966          parameters.getBooleanParameter(blindTrustParameter.getName());
967     if (blindTrustParam != null)
968     {
969       blindTrust = blindTrustParam.getBooleanValue();
970     }
971
972
973     String JavaDoc keyStore = null;
974     StringParameter keyStoreParam =
975          parameters.getStringParameter(sslKeyStoreParameter.getName());
976     if ((keyStoreParam != null) && keyStoreParam.hasValue())
977     {
978       keyStore = keyStoreParam.getStringValue();
979       File keyStoreFile = new File(keyStore);
980       if (useSSL && (! blindTrust) && (! keyStoreFile.exists()))
981       {
982         outputMessages.add("WARNING: Key store file \"" + keyStore +
983                            "\" not found on SLAMD server system. This test " +
984                            "will blindly trust any SSL certificate " +
985                            "presented by the directory server.");
986         outputMessages.add("");
987         blindTrust = true;
988       }
989       else
990       {
991         System.setProperty(SSL_KEY_STORE_PROPERTY, keyStore);
992       }
993     }
994
995
996     String JavaDoc keyStorePassword = "";
997     StringParameter keyPassParam =
998          parameters.getStringParameter(sslKeyPWParameter.getName());
999     if ((keyPassParam != null) && keyPassParam.hasValue())
1000    {
1001      keyStorePassword = keyPassParam.getStringValue();
1002      System.setProperty(SSL_KEY_PASSWORD_PROPERTY, keyStorePassword);
1003    }
1004
1005
1006    String JavaDoc trustStore = null;
1007    StringParameter trustStoreParam =
1008         parameters.getStringParameter(sslTrustStoreParameter.getName());
1009    if ((trustStoreParam != null) && trustStoreParam.hasValue())
1010    {
1011      trustStore = trustStoreParam.getStringValue();
1012      File trustStoreFile = new File(trustStore);
1013      if (useSSL && (! blindTrust) && (! trustStoreFile.exists()))
1014      {
1015        outputMessages.add("WARNING: trust store file \"" + trustStore +
1016                           "\" not found on SLAMD server system. This test " +
1017                           "will blindly trust any SSL certificate " +
1018                           "presented by the directory server.");
1019        outputMessages.add("");
1020        blindTrust = true;
1021      }
1022      else
1023      {
1024        System.setProperty(SSL_TRUST_STORE_PROPERTY, trustStore);
1025      }
1026    }
1027
1028
1029    String JavaDoc trustStorePassword = "";
1030    StringParameter trustPassParam =
1031         parameters.getStringParameter(sslTrustPWParameter.getName());
1032    if ((trustPassParam != null) && trustPassParam.hasValue())
1033    {
1034      trustStorePassword = trustPassParam.getStringValue();
1035      System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, trustStorePassword);
1036    }
1037
1038
1039    String JavaDoc bindDN = "";
1040    StringParameter bindDNParam =
1041         parameters.getStringParameter(bindDNParameter.getName());
1042    if ((bindDNParam != null) && bindDNParam.hasValue())
1043    {
1044      bindDN = bindDNParam.getStringValue();
1045    }
1046
1047
1048    String JavaDoc bindPassword = "";
1049    PasswordParameter bindPWParam =
1050         parameters.getPasswordParameter(bindPasswordParameter.getName());
1051    if ((bindPWParam != null) && bindPWParam.hasValue())
1052    {
1053      bindPassword = bindPWParam.getStringValue();
1054    }
1055
1056
1057    String JavaDoc proxyAsDN = null;
1058    StringParameter proxyAsDNParam =
1059         parameters.getStringParameter(proxyAsDNParameter.getName());
1060    if ((proxyAsDNParam != null) && proxyAsDNParam.hasValue())
1061    {
1062      proxyAsDN = proxyAsDNParam.getStringValue();
1063    }
1064
1065
1066    StringParameter baseDNParam =
1067         parameters.getStringParameter(baseDNParameter.getName());
1068    if ((baseDNParam == null) || (! baseDNParam.hasValue()))
1069    {
1070      outputMessages.add("ERROR: No base DN was provided.");
1071      return false;
1072    }
1073    String JavaDoc baseDN = baseDNParam.getStringValue();
1074
1075
1076    // Create the LDAPConnection object that we will use to communicate with the
1077
// directory server.
1078
LDAPConnection conn;
1079    if (useSSL)
1080    {
1081      if (blindTrust)
1082      {
1083        try
1084        {
1085          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1086        }
1087        catch (Exception JavaDoc e)
1088        {
1089          outputMessages.add("ERROR: Unable to instantiate the blind trust " +
1090                             "socket factory for use in creating the SSL " +
1091                             "connection: " + stackTraceToString(e));
1092          return false;
1093        }
1094      }
1095      else
1096      {
1097        conn = new LDAPConnection(new JSSESocketFactory(null));
1098      }
1099    }
1100    else
1101    {
1102      conn = new LDAPConnection();
1103    }
1104
1105
1106    // Attempt to establish a connection to the directory server.
1107
try
1108    {
1109      if (useSSL)
1110      {
1111        outputMessages.add("Attempting to establish an SSL-based connection " +
1112                           "to " + host + ":" + port + "....");
1113      }
1114      else
1115      {
1116        outputMessages.add("Attempting to establish a connection to " + host +
1117                           ":" + port + "....");
1118      }
1119      conn.connect(host, port);
1120      outputMessages.add("Connected successfully.");
1121      outputMessages.add("");
1122    }
1123    catch (Exception JavaDoc e)
1124    {
1125      outputMessages.add("ERROR: Unable to connect to the directory " +
1126                         "server: " + stackTraceToString(e));
1127      return false;
1128    }
1129
1130
1131    // Attempt to bind to the directory server using the bind DN and password.
1132
try
1133    {
1134      outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
1135                         "directory server with a DN of '" + bindDN + "'....");
1136      conn.bind(3, bindDN, bindPassword);
1137      outputMessages.add("Bound successfully.");
1138      outputMessages.add("");
1139    }
1140    catch (Exception JavaDoc e)
1141    {
1142      try
1143      {
1144        conn.disconnect();
1145      } catch (Exception JavaDoc e2) {}
1146
1147      outputMessages.add("ERROR: Unable to bind to the directory server: " +
1148                         stackTraceToString(e));
1149      return false;
1150    }
1151
1152
1153    // If a proxy user was specified, make sure that it exists.
1154
if (proxyAsDN != null)
1155    {
1156      try
1157      {
1158        outputMessages.add("Checking to make sure that the proxied user '" +
1159                           proxyAsDN + "' exists in the directory....");
1160        LDAPEntry proxyUserEntry = conn.read(proxyAsDN, new String JavaDoc[] { "1.1" });
1161        if (proxyUserEntry == null)
1162        {
1163          try
1164          {
1165            conn.disconnect();
1166          } catch (Exception JavaDoc e2) {}
1167
1168          outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
1169                             "entry.");
1170          return false;
1171        }
1172        else
1173        {
1174          outputMessages.add("Successfully read the proxied user's entry.");
1175          outputMessages.add("");
1176        }
1177      }
1178      catch (Exception JavaDoc e)
1179      {
1180        try
1181        {
1182          conn.disconnect();
1183        } catch (Exception JavaDoc e2) {}
1184
1185        outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
1186                           "entry: " + stackTraceToString(e));
1187        return false;
1188      }
1189    }
1190
1191
1192    // Make sure that the entry specified as the base DN exists.
1193
try
1194    {
1195      outputMessages.add("Checking to make sure that the base DN entry '" +
1196                         baseDN + "' exists in the directory....");
1197      LDAPEntry baseDNEntry = conn.read(baseDN, new String JavaDoc[] { "1.1" });
1198      if (baseDNEntry == null)
1199      {
1200        try
1201        {
1202          conn.disconnect();
1203        } catch (Exception JavaDoc e2) {}
1204
1205        outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
1206        return false;
1207      }
1208      else
1209      {
1210        outputMessages.add("Successfully read the base DN entry.");
1211        outputMessages.add("");
1212      }
1213    }
1214    catch (Exception JavaDoc e)
1215    {
1216      try
1217      {
1218        conn.disconnect();
1219      } catch (Exception JavaDoc e2) {}
1220
1221      outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
1222                         stackTraceToString(e));
1223      return false;
1224    }
1225
1226
1227    // At this point, all tests have passed. Close the connection and return
1228
// true.
1229
try
1230    {
1231      conn.disconnect();
1232    } catch (Exception JavaDoc e) {}
1233
1234    outputMessages.add("All tests completed successfully.");
1235    return true;
1236  }
1237
1238
1239
1240  /**
1241   * Performs client-level initialization for this job, including retrieving
1242   * the values of all the parameters and reading the filter file (if one has
1243   * been specified).
1244   *
1245   * @param clientID The ID assigned to the client that will be running the
1246   * job.
1247   * @param parameters The list of parameters defined for this job.
1248   *
1249   * @throws UnableToRunException If the initialization fails for some reason.
1250   */

1251  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1252         throws UnableToRunException
1253  {
1254    // Get the address of the directory server.
1255
ldapHost = null;
1256    addressParameter =
1257         parameters.getStringParameter(addressParameter.getName());
1258    if ((addressParameter != null) && addressParameter.hasValue())
1259    {
1260      ldapHost = addressParameter.getStringValue();
1261    }
1262
1263    // Get the port for the directory server.
1264
ldapPort = 389;
1265    portParameter = parameters.getIntegerParameter(portParameter.getName());
1266    if ((portParameter != null) && portParameter.hasValue())
1267    {
1268      ldapPort = portParameter.getIntValue();
1269    }
1270
1271    // Get the base DN.
1272
baseDN = null;
1273    baseDNParameter = parameters.getStringParameter(baseDNParameter.getName());
1274    if ((baseDNParameter != null) && baseDNParameter.hasValue())
1275    {
1276      baseDN = baseDNParameter.getStringValue();
1277
1278    }
1279
1280    // Get the bind DN.
1281
bindDN = "";
1282    bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1283    if ((bindDNParameter != null) && bindDNParameter.hasValue())
1284    {
1285      bindDN = bindDNParameter.getStringValue();
1286    }
1287
1288    // Get the bind password.
1289
bindPW = "";
1290    bindPasswordParameter =
1291         parameters.getPasswordParameter(bindPasswordParameter.getName());
1292    if ((bindPasswordParameter != null) && bindPasswordParameter.hasValue())
1293    {
1294      bindPW = bindPasswordParameter.getStringValue();
1295    }
1296
1297    // Get the proxy as DN.
1298
proxyAsDN = null;
1299    proxyAsDNParameter =
1300         parameters.getStringParameter(proxyAsDNParameter.getName());
1301    if ((proxyAsDNParameter != null) && proxyAsDNParameter.hasValue())
1302    {
1303      proxyAsDNParameter.getStringValue();
1304    }
1305
1306    // Get the add frequency.
1307
addFrequency = 0;
1308    addFrequencyParameter =
1309         parameters.getIntegerParameter(addFrequencyParameter.getName());
1310    if ((addFrequencyParameter != null) && addFrequencyParameter.hasValue())
1311    {
1312      addFrequency = addFrequencyParameter.getIntValue();
1313    }
1314
1315    // Get the compare frequency.
1316
compareFrequency = 0;
1317    compareFrequencyParameter =
1318         parameters.getIntegerParameter(compareFrequencyParameter.getName());
1319    if ((compareFrequencyParameter != null) &&
1320        compareFrequencyParameter.hasValue())
1321    {
1322      compareFrequency = compareFrequencyParameter.getIntValue();
1323    }
1324
1325    // Get the delete frequency.
1326
deleteFrequency = 0;
1327    deleteFrequencyParameter =
1328         parameters.getIntegerParameter(deleteFrequencyParameter.getName());
1329    if ((deleteFrequencyParameter != null) &&
1330        deleteFrequencyParameter.hasValue())
1331    {
1332      deleteFrequency = deleteFrequencyParameter.getIntValue();
1333    }
1334
1335    // Get the modify frequency.
1336
modifyFrequency = 0;
1337    modifyFrequencyParameter =
1338         parameters.getIntegerParameter(modifyFrequencyParameter.getName());
1339    if ((modifyFrequencyParameter != null) &&
1340        modifyFrequencyParameter.hasValue())
1341    {
1342      modifyFrequency = modifyFrequencyParameter.getIntValue();
1343    }
1344
1345    // Get the modify RDN frequency.
1346
modifyRDNFrequency = 0;
1347    modifyRDNFrequencyParameter =
1348         parameters.getIntegerParameter(modifyRDNFrequencyParameter.getName());
1349    if ((modifyRDNFrequencyParameter != null) &&
1350        modifyRDNFrequencyParameter.hasValue())
1351    {
1352      modifyRDNFrequency = modifyRDNFrequencyParameter.getIntValue();
1353    }
1354
1355    // Get the search frequency.
1356
searchFrequency = 0;
1357    searchFrequencyParameter =
1358         parameters.getIntegerParameter(searchFrequencyParameter.getName());
1359    if ((searchFrequencyParameter != null) &&
1360        searchFrequencyParameter.hasValue())
1361    {
1362      searchFrequency = searchFrequencyParameter.getIntValue();
1363    }
1364
1365    // Calculate the total of all the frequencies and create the frequency array
1366
totalFrequency = addFrequency + compareFrequency + deleteFrequency +
1367                     modifyFrequency + modifyRDNFrequency + searchFrequency;
1368    opWeights = new int[6];
1369    opWeights[0] = addFrequency;
1370    opWeights[1] = opWeights[0] + compareFrequency;
1371    opWeights[2] = opWeights[1] + deleteFrequency;
1372    opWeights[3] = opWeights[2] + modifyFrequency;
1373    opWeights[4] = opWeights[3] + modifyRDNFrequency;
1374    opWeights[5] = opWeights[4] + searchFrequency;
1375
1376    // Get the DN or list of DNs to use.
1377
dnFileURLParameter =
1378         parameters.getFileURLParameter(dnFileURLParameter.getName());
1379    if ((dnFileURLParameter != null) && (dnFileURLParameter.hasValue()))
1380    {
1381      try
1382      {
1383        entryDNs = dnFileURLParameter.getNonBlankFileLines();
1384      }
1385      catch (Exception JavaDoc e)
1386      {
1387        throw new UnableToRunException("Unable to retrieve DN list: " + e, e);
1388      }
1389    }
1390    else
1391    {
1392      dnParameter = parameters.getStringParameter(dnParameter.getName());
1393      if ((dnParameter == null) || (! dnParameter.hasValue()))
1394      {
1395        throw new UnableToRunException("No DN file or entry DN specified.");
1396      }
1397
1398      String JavaDoc entryDN = dnParameter.getStringValue();
1399      int openPos = entryDN.indexOf('[');
1400      if (openPos >= 0)
1401      {
1402        int dashPos = entryDN.indexOf('-', openPos);
1403        useDNRange = true;
1404        useSequentialDNs = false;
1405
1406        if (dashPos == 0)
1407        {
1408          dashPos = entryDN.indexOf(':');
1409          useSequentialDNs = true;
1410        }
1411
1412        int closePos = entryDN.indexOf(']', dashPos);
1413        dnMin = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
1414        dnMax = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1415        dnSpan = (dnMax - dnMin) + 1;
1416        dnInitial = entryDN.substring(0, openPos);
1417        dnFinal = entryDN.substring(closePos+1);
1418        nextDN = dnMin;
1419      }
1420      else
1421      {
1422        useDNRange = false;
1423        dnInitial = entryDN;
1424      }
1425    }
1426
1427    // Get the filter or list of filters to use.
1428
filterFileURLParameter =
1429         parameters.getFileURLParameter(filterFileURLParameter.getName());
1430    if ((filterFileURLParameter != null) && (filterFileURLParameter.hasValue()))
1431    {
1432      try
1433      {
1434        searchFilters = filterFileURLParameter.getNonBlankFileLines();
1435      }
1436      catch (Exception JavaDoc e)
1437      {
1438        throw new UnableToRunException("Unable to retrieve filter list: " + e,
1439                                       e);
1440      }
1441    }
1442    else
1443    {
1444      filterParameter =
1445           parameters.getStringParameter(filterParameter.getName());
1446      if ((filterParameter == null) || (! filterParameter.hasValue()))
1447      {
1448        throw new UnableToRunException("No filter file or filter list " +
1449                                       "specified.");
1450      }
1451
1452      String JavaDoc filter = filterParameter.getStringValue();
1453      int openPos = filter.indexOf('[');
1454      if (openPos >= 0)
1455      {
1456        int dashPos = filter.indexOf('-', openPos);
1457        useFilterRange = true;
1458        useSequentialFilters = false;
1459
1460        if (dashPos == 0)
1461        {
1462          dashPos = filter.indexOf(':');
1463          useSequentialFilters = true;
1464        }
1465
1466        int closePos = filter.indexOf(']', dashPos);
1467        filterMin = Integer.parseInt(filter.substring(openPos+1, dashPos));
1468        filterMax = Integer.parseInt(filter.substring(dashPos+1, closePos));
1469        filterSpan = (filterMax - filterMin) + 1;
1470        filterInitial = filter.substring(0, openPos);
1471        filterFinal = filter.substring(closePos+1);
1472        nextFilter = filterMin;
1473      }
1474      else
1475      {
1476        useFilterRange = false;
1477        filterInitial = filter;
1478      }
1479    }
1480
1481    // Get the attribute to compare/modify
1482
attrParameter = parameters.getStringParameter(attrParameter.getName());
1483    if ((attrParameter != null) && attrParameter.hasValue())
1484    {
1485      modAttr = attrParameter.getStringValue();
1486    }
1487
1488    // Get the size limit
1489
sizeLimit = 0;
1490    sizeLimitParameter =
1491         parameters.getIntegerParameter(sizeLimitParameter.getName());
1492    if ((sizeLimitParameter != null) && sizeLimitParameter.hasValue())
1493    {
1494      sizeLimit = sizeLimitParameter.getIntValue();
1495    }
1496
1497    // Get the time limit
1498
timeLimit = 0;
1499    timeLimitParameter =
1500         parameters.getIntegerParameter(timeLimitParameter.getName());
1501    if ((timeLimitParameter != null) && timeLimitParameter.hasValue())
1502    {
1503      timeLimit = timeLimitParameter.getIntValue();
1504    }
1505
1506    // Get the warm-up time.
1507
warmUpTime = 0;
1508    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1509    if ((warmUpParameter != null) && warmUpParameter.hasValue())
1510    {
1511      warmUpTime = warmUpParameter.getIntValue();
1512    }
1513
1514    // Get the cool-down time.
1515
coolDownTime = 0;
1516    coolDownParameter =
1517         parameters.getIntegerParameter(coolDownParameter.getName());
1518    if ((coolDownParameter != null) && coolDownParameter.hasValue())
1519    {
1520      coolDownTime = coolDownParameter.getIntValue();
1521    }
1522
1523    // Get the time between requests
1524
operationDelay = 0;
1525    delayParameter =
1526         parameters.getIntegerParameter(delayParameter.getName());
1527    if ((delayParameter != null) && delayParameter.hasValue())
1528    {
1529      operationDelay = delayParameter.getIntValue();
1530    }
1531
1532    // Get the use SSL flag
1533
useSSL = false;
1534    useSSLParameter =
1535         parameters.getBooleanParameter(useSSLParameter.getName());
1536    if (useSSLParameter != null)
1537    {
1538      useSSL = useSSLParameter.getBooleanValue();
1539    }
1540
1541    if (useSSL)
1542    {
1543      // See if we should blindly trust any certificate.
1544
blindTrustParameter =
1545           parameters.getBooleanParameter(blindTrustParameter.getName());
1546      if (blindTrustParameter != null)
1547      {
1548        blindTrust = blindTrustParameter.getBooleanValue();
1549      }
1550
1551      // Get the SSL key store
1552
sslKeyStoreParameter =
1553           parameters.getStringParameter(sslKeyStoreParameter.getName());
1554      if ((sslKeyStoreParameter != null) && sslKeyStoreParameter.hasValue())
1555      {
1556        sslKeyStore = sslKeyStoreParameter.getStringValue();
1557        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1558      }
1559
1560      // Get the SSL key password
1561
sslKeyPWParameter =
1562           parameters.getPasswordParameter(sslKeyPWParameter.getName());
1563      if ((sslKeyPWParameter != null) && sslKeyPWParameter.hasValue())
1564      {
1565        sslKeyPW = sslKeyPWParameter.getStringValue();
1566        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPW);
1567      }
1568
1569      // Get the SSL trust store
1570
sslTrustStoreParameter =
1571           parameters.getStringParameter(sslTrustStoreParameter.getName());
1572      if ((sslTrustStoreParameter != null) && sslTrustStoreParameter.hasValue())
1573      {
1574        sslTrustStore = sslTrustStoreParameter.getStringValue();
1575        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1576      }
1577
1578      // Get the SSL trust password
1579
sslTrustPWParameter =
1580           parameters.getPasswordParameter(sslTrustPWParameter.getName());
1581      if ((sslTrustPWParameter != null) && sslTrustPWParameter.hasValue())
1582      {
1583        sslTrustPW = sslTrustPWParameter.getStringValue();
1584        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPW);
1585      }
1586    }
1587
1588    // Determine whether to perform cleanup after the job is done.
1589
cleanUp = true;
1590    cleanUpParameter =
1591         parameters.getBooleanParameter(cleanUpParameter.getName());
1592    if (cleanUpParameter != null)
1593    {
1594      cleanUp = cleanUpParameter.getBooleanValue();
1595    }
1596
1597    // Get the always disconnect flag
1598
alwaysDisconnect = false;
1599    disconnectParameter =
1600         parameters.getBooleanParameter(disconnectParameter.getName());
1601    if (disconnectParameter != null)
1602    {
1603      alwaysDisconnect = disconnectParameter.getBooleanValue();
1604    }
1605
1606    // Get the follow referrals flag
1607
followReferrals = false;
1608    referralsParameter =
1609         parameters.getBooleanParameter(referralsParameter.getName());
1610    if (referralsParameter != null)
1611    {
1612      followReferrals = referralsParameter.getBooleanValue();
1613    }
1614
1615    // Initialize the parent random number generator.
1616
parentRandom = new Random();
1617
1618
1619    // Make sure that the list of DNs to delete is empty.
1620
addedDNs.clear();
1621    dnsToDelete = 0;
1622  }
1623
1624
1625  /**
1626   * Initializes this job thread to be used to actually run the job on the
1627   * client. The provided parameter list should be processed to customize the
1628   * behavior of this job thread, and any other initialization that needs to be
1629   * done in order for the job to run should be performed here as well.
1630   *
1631   * @param clientID The client ID for this job thread.
1632   * @param threadID The thread ID for this job thread.
1633   * @param collectionInterval The length of time in seconds to use as the
1634   * statistics collection interval.
1635   * @param parameters The set of parameters provided to this job that
1636   * can be used to customize its behavior.
1637   *
1638   * @throws UnableToRunException If a problem occurs that prevents the thread
1639   * from being able to run properly.
1640   */

1641  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1642                               int collectionInterval, ParameterList parameters)
1643         throws UnableToRunException
1644  {
1645    // Create all the stat trackers.
1646
addCount = new IncrementalTracker(clientID, threadID,
1647                                            STAT_TRACKER_ADD_ATTEMPTS,
1648                                            collectionInterval);
1649    compareCount = new IncrementalTracker(clientID, threadID,
1650                                            STAT_TRACKER_COMPARE_ATTEMPTS,
1651                                            collectionInterval);
1652    deleteCount = new IncrementalTracker(clientID, threadID,
1653                                            STAT_TRACKER_DELETE_ATTEMPTS,
1654                                            collectionInterval);
1655    modifyCount = new IncrementalTracker(clientID, threadID,
1656                                            STAT_TRACKER_MODIFY_ATTEMPTS,
1657                                            collectionInterval);
1658    modifyRDNCount = new IncrementalTracker(clientID, threadID,
1659                                            STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
1660                                            collectionInterval);
1661    searchCount = new IncrementalTracker(clientID, threadID,
1662                                            STAT_TRACKER_SEARCH_ATTEMPTS,
1663                                            collectionInterval);
1664    operationCount = new IncrementalTracker(clientID, threadID,
1665                                            STAT_TRACKER_OPERATION_ATTEMPTS,
1666                                            collectionInterval);
1667    addTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
1668                                     collectionInterval);
1669    compareTimer = new TimeTracker(clientID, threadID,
1670                                     STAT_TRACKER_COMPARE_TIME,
1671                                     collectionInterval);
1672    deleteTimer = new TimeTracker(clientID, threadID,
1673                                     STAT_TRACKER_DELETE_TIME,
1674                                     collectionInterval);
1675    modifyTimer = new TimeTracker(clientID, threadID,
1676                                     STAT_TRACKER_MODIFY_TIME,
1677                                     collectionInterval);
1678    modifyRDNTimer = new TimeTracker(clientID, threadID,
1679                                     STAT_TRACKER_MODIFY_RDN_TIME,
1680                                     collectionInterval);
1681    searchTimer = new TimeTracker(clientID, threadID,
1682                                     STAT_TRACKER_SEARCH_TIME,
1683                                     collectionInterval);
1684    operationTimer = new TimeTracker(clientID, threadID,
1685                                     STAT_TRACKER_OPERATION_TIME,
1686                                     collectionInterval);
1687    resultCodes = new CategoricalTracker(clientID, threadID,
1688                                            STAT_TRACKER_RESULT_CODES,
1689                                            collectionInterval);
1690    operationTypes =
1691         new CategoricalTracker(clientID, threadID,
1692                                STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
1693                                collectionInterval);
1694
1695
1696    // Enable real-time reporting of the data for these stat trackers.
1697
RealTimeStatReporter statReporter = getStatReporter();
1698    if (statReporter != null)
1699    {
1700      String JavaDoc jobID = getJobID();
1701      addCount.enableRealTimeStats(statReporter, jobID);
1702      compareCount.enableRealTimeStats(statReporter, jobID);
1703      deleteCount.enableRealTimeStats(statReporter, jobID);
1704      modifyCount.enableRealTimeStats(statReporter, jobID);
1705      modifyRDNCount.enableRealTimeStats(statReporter, jobID);
1706      searchCount.enableRealTimeStats(statReporter, jobID);
1707      operationCount.enableRealTimeStats(statReporter, jobID);
1708      addTimer.enableRealTimeStats(statReporter, jobID);
1709      compareTimer.enableRealTimeStats(statReporter, jobID);
1710      deleteTimer.enableRealTimeStats(statReporter, jobID);
1711      modifyTimer.enableRealTimeStats(statReporter, jobID);
1712      modifyRDNTimer.enableRealTimeStats(statReporter, jobID);
1713      searchTimer.enableRealTimeStats(statReporter, jobID);
1714      operationTimer.enableRealTimeStats(statReporter, jobID);
1715    }
1716
1717
1718    // Create the random number generator for this thread
1719
random = new Random(parentRandom.nextLong());
1720
1721
1722    // If SSL will be used, then establish an SSL-based connection to the
1723
// directory server. When using JSSE, the first connection always takes
1724
// longer than the subsequent connections, so we want to get that out of the
1725
// way before the job actually starts running.
1726
if (useSSL)
1727    {
1728      try
1729      {
1730        if (blindTrust)
1731        {
1732          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1733        }
1734        else
1735        {
1736          conn = new LDAPConnection(new JSSESocketFactory(null));
1737        }
1738        conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
1739        conn.disconnect();
1740      }
1741      catch (Exception JavaDoc e)
1742      {
1743        throw new UnableToRunException("Unable to establish an SSL-based " +
1744                                       "connection to the directory: " + e, e);
1745      }
1746    }
1747    else
1748    {
1749      conn = new LDAPConnection();
1750    }
1751  }
1752
1753
1754
1755  /**
1756   * Perform the work of this job thread by establishing the connection(s) to
1757   * the directory server and issuing all the appropriate queries. The job will
1758   * continue until the specified number of iterations have been performed, the
1759   * stop time has been reached, the maximum duration has been reached, or the
1760   * SLAMD server indicates that a stop has been requested.
1761   */

1762  public void runJob()
1763  {
1764    // Determine the range of time for which we should collect statistics.
1765
long currentTime = System.currentTimeMillis();
1766    collectingStats = false;
1767    long startCollectingTime = currentTime + (1000 * warmUpTime);
1768    long stopCollectingTime = Long.MAX_VALUE;
1769    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1770    {
1771      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1772    }
1773
1774
1775    // Set a variable that we can use to determine if the connection is alive
1776
boolean connected = false;
1777
1778
1779    // Create a loop that will run for the appropriate length of time.
1780
while (! shouldStop())
1781    {
1782      long opStartTime = System.currentTimeMillis();
1783      if ((! collectingStats) && (opStartTime >= startCollectingTime) &&
1784          (opStartTime <= stopCollectingTime))
1785      {
1786        // Tell the stat trackers that they should start tracking now
1787
addCount.startTracker();
1788        compareCount.startTracker();
1789        deleteCount.startTracker();
1790        modifyCount.startTracker();
1791        modifyRDNCount.startTracker();
1792        searchCount.startTracker();
1793        operationCount.startTracker();
1794        addTimer.startTracker();
1795        compareTimer.startTracker();
1796        deleteTimer.startTracker();
1797        modifyTimer.startTracker();
1798        modifyRDNTimer.startTracker();
1799        searchTimer.startTracker();
1800        operationTimer.startTracker();
1801        operationTypes.startTracker();
1802        resultCodes.startTracker();
1803        collectingStats = true;
1804      }
1805      else if ((collectingStats) && (opStartTime >= stopCollectingTime))
1806      {
1807        addCount.stopTracker();
1808        compareCount.stopTracker();
1809        deleteCount.stopTracker();
1810        modifyCount.stopTracker();
1811        modifyRDNCount.stopTracker();
1812        searchCount.stopTracker();
1813        operationCount.stopTracker();
1814        addTimer.stopTracker();
1815        compareTimer.stopTracker();
1816        deleteTimer.stopTracker();
1817        modifyTimer.stopTracker();
1818        modifyRDNTimer.stopTracker();
1819        searchTimer.stopTracker();
1820        operationTimer.stopTracker();
1821        operationTypes.stopTracker();
1822        resultCodes.stopTracker();
1823        collectingStats = false;
1824      }
1825
1826
1827      // If the connection is currently not connected, then establish it
1828
if (! connected)
1829      {
1830        try
1831        {
1832          conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
1833          connected = true;
1834
1835          // Create the constraints for this connection.
1836
constraints = conn.getConstraints();
1837          constraints.setTimeLimit(1000*timeLimit);
1838          constraints.setRebindProc(this);
1839          constraints.setReferrals(followReferrals);
1840
1841          // Create the search constraints for this connection
1842
searchConstraints = conn.getSearchConstraints();
1843          searchConstraints.setMaxResults(sizeLimit);
1844          searchConstraints.setTimeLimit(1000*timeLimit);
1845          searchConstraints.setServerTimeLimit(timeLimit);
1846          searchConstraints.setRebindProc(this);
1847          searchConstraints.setReferrals(followReferrals);
1848
1849          if ((proxyAsDN != null) && (proxyAsDN.length() > 0))
1850          {
1851            LDAPProxiedAuthControl proxyControl =
1852                 new LDAPProxiedAuthControl(proxyAsDN, true);
1853            constraints.setServerControls(proxyControl);
1854            searchConstraints.setServerControls(proxyControl);
1855          }
1856        }
1857        catch (Exception JavaDoc e)
1858        {
1859          logMessage("ERROR -- Could not connect to " + ldapHost + ":" +
1860                     ldapPort + " (" + e + ") -- aborting thread");
1861          if (collectingStats)
1862          {
1863            if (e instanceof LDAPException)
1864            {
1865              int resultCode = ((LDAPException) e).getLDAPResultCode();
1866              resultCodes.increment(String.valueOf(resultCode));
1867            }
1868            else
1869            {
1870              String JavaDoc category = String.valueOf(LDAPException.CONNECT_ERROR);
1871              resultCodes.increment(category);
1872            }
1873          }
1874          indicateStoppedDueToError();
1875          break;
1876        }
1877      }
1878
1879
1880      // Pick the type of operation to perform and then do it.
1881
int resultCode;
1882      int opType = (random.nextInt() & 0x7FFFFFFF) % totalFrequency;
1883
1884      if (collectingStats)
1885      {
1886        operationCount.increment();
1887        operationTimer.startTimer();
1888      }
1889
1890      if (opType < opWeights[0])
1891      {
1892        if (collectingStats)
1893        {
1894          operationTypes.increment("Add");
1895        }
1896        resultCode = doAdd();
1897      }
1898      else if (opType < opWeights[1])
1899      {
1900        if (collectingStats)
1901        {
1902          operationTypes.increment("Compare");
1903        }
1904        resultCode = doCompare();
1905      }
1906      else if (opType < opWeights[2])
1907      {
1908        if (collectingStats)
1909        {
1910          operationTypes.increment("Delete");
1911        }
1912        resultCode = doDelete();
1913      }
1914      else if (opType < opWeights[3])
1915      {
1916        if (collectingStats)
1917        {
1918          operationTypes.increment("Modify");
1919        }
1920        resultCode = doModify();
1921      }
1922      else if (opType < opWeights[4])
1923      {
1924        if (collectingStats)
1925        {
1926          operationTypes.increment("Modify RDN");
1927        }
1928        resultCode = doModifyRDN();
1929      }
1930      else
1931      {
1932        if (collectingStats)
1933        {
1934          operationTypes.increment("Search");
1935        }
1936        resultCode = doSearch();
1937      }
1938
1939      if (collectingStats)
1940      {
1941        operationTimer.stopTimer();
1942        resultCodes.increment(String.valueOf(resultCode));
1943      }
1944
1945
1946      // See if we need to close the connection to the directory.
1947
if (alwaysDisconnect)
1948      {
1949        try
1950        {
1951          conn.disconnect();
1952        } catch (Exception JavaDoc e) {}
1953        connected = false;
1954      }
1955
1956
1957      // See if we need to sleep until the next operation.
1958
if (operationDelay > 0)
1959      {
1960        long opTime = System.currentTimeMillis() - opStartTime;
1961        if ((opTime < operationDelay) && (! shouldStop()))
1962        {
1963          try
1964          {
1965            Thread.sleep(operationDelay - opTime);
1966          } catch (InterruptedException JavaDoc ie) {}
1967        }
1968      }
1969    }
1970
1971
1972    // If we are still collecting statistics, then stop.
1973
if (collectingStats)
1974    {
1975      addCount.stopTracker();
1976      compareCount.stopTracker();
1977      deleteCount.stopTracker();
1978      modifyCount.stopTracker();
1979      modifyRDNCount.stopTracker();
1980      searchCount.stopTracker();
1981      operationCount.stopTracker();
1982      addTimer.stopTracker();
1983      compareTimer.stopTracker();
1984      deleteTimer.stopTracker();
1985      modifyTimer.stopTracker();
1986      modifyRDNTimer.stopTracker();
1987      searchTimer.stopTracker();
1988      operationTimer.stopTracker();
1989      operationTypes.stopTracker();
1990      resultCodes.stopTracker();
1991    }
1992
1993
1994    // If we are still connected to the directory, then disconnect.
1995
try
1996    {
1997      conn.disconnect();
1998    } catch (Exception JavaDoc e) {}
1999  }
2000
2001
2002
2003  /**
2004   * Performs any per-client finalization that should be done for this job. In
2005   * this case, it will clean up any entries that may still be left over from
2006   * processing.
2007   */

2008  public void finalizeClient()
2009  {
2010    if (cleanUp)
2011    {
2012      if (useSSL)
2013      {
2014        try
2015        {
2016          if (blindTrust)
2017          {
2018            conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
2019          }
2020          else
2021          {
2022            conn = new LDAPConnection(new JSSESocketFactory(null));
2023          }
2024        }
2025        catch (Exception JavaDoc e)
2026        {
2027          logMessage("Unable to establish an SSL-based connection to the " +
2028                     "directory to perform cleanup: " + e);
2029          return;
2030        }
2031      }
2032      else
2033      {
2034        conn = new LDAPConnection();
2035      }
2036
2037      try
2038      {
2039        conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
2040      }
2041      catch (Exception JavaDoc e)
2042      {
2043        logMessage("Unable to establish a connection to the directory to " +
2044                   "perform cleanup: " + e);
2045        return;
2046      }
2047
2048      LDAPConstraints constraints = conn.getConstraints();
2049      if (proxyAsDN != null)
2050      {
2051        LDAPProxiedAuthControl proxyControl =
2052             new LDAPProxiedAuthControl(proxyAsDN, true);
2053        constraints.setServerControls(proxyControl);
2054      }
2055
2056
2057      while (! addedDNs.isEmpty())
2058      {
2059        String JavaDoc dnToDelete = (String JavaDoc) addedDNs.removeFirst();
2060
2061        try
2062        {
2063          conn.delete(dnToDelete, constraints);
2064        }
2065        catch (LDAPException le)
2066        {
2067          logMessage("Unable to perform cleanup -- exception thrown while " +
2068                     "trying to delete entry \"" + dnToDelete + "\": " + le);
2069          try
2070          {
2071            conn.disconnect();
2072          } catch (Exception JavaDoc e) {}
2073          return;
2074        }
2075      }
2076
2077      try
2078      {
2079        conn.disconnect();
2080      } catch (Exception JavaDoc e) {}
2081    }
2082  }
2083
2084
2085
2086  /**
2087   * Attempts to force this thread to exit by closing the connection to the
2088   * directory server and setting it to <CODE>null</CODE>.
2089   */

2090  public void destroy()
2091  {
2092    if (conn != null)
2093    {
2094      try
2095      {
2096        conn.disconnect();
2097      } catch (Exception JavaDoc e) {}
2098
2099      conn = null;
2100    }
2101  }
2102
2103
2104
2105  /**
2106   * Performs an add operation in the directory.
2107   *
2108   * @return The result code of the add operation.
2109   */

2110  public int doAdd()
2111  {
2112    int resultCode = LDAPException.SUCCESS;
2113    LDAPEntry entry = getEntry();
2114    String JavaDoc entryDN = entry.getDN();
2115
2116    if (collectingStats)
2117    {
2118      addCount.increment();
2119      addTimer.startTimer();
2120    }
2121
2122    try
2123    {
2124      conn.add(entry, constraints);
2125      addDNToDelete(entryDN);
2126    }
2127    catch (LDAPException le)
2128    {
2129      resultCode = le.getLDAPResultCode();
2130    }
2131
2132    if (collectingStats)
2133    {
2134      addTimer.stopTimer();
2135    }
2136
2137    return resultCode;
2138  }
2139
2140
2141
2142  /**
2143   * Performs a compare operation in the directory.
2144   *
2145   * @return The result code of the compare operation.
2146   */

2147  public int doCompare()
2148  {
2149    int resultCode;
2150
2151    String JavaDoc dn = getEntryDN();
2152    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2153
2154    if (collectingStats)
2155    {
2156      compareCount.increment();
2157      compareTimer.startTimer();
2158    }
2159
2160    try
2161    {
2162      resultCode = conn.compare(dn, attr, constraints)
2163                   ? LDAPException.COMPARE_TRUE
2164                   : LDAPException.COMPARE_FALSE;
2165    }
2166    catch (LDAPException le)
2167    {
2168      resultCode = le.getLDAPResultCode();
2169    }
2170
2171    if (collectingStats)
2172    {
2173      compareTimer.stopTimer();
2174    }
2175
2176    return resultCode;
2177  }
2178
2179
2180
2181  /**
2182   * Performs a delete operation in the directory.
2183   *
2184   * @return The result code of the delete operation.
2185   */

2186  public int doDelete()
2187  {
2188    int resultCode = LDAPException.SUCCESS;
2189    String JavaDoc dn = getDNToDelete();
2190
2191    if (dn == null)
2192    {
2193      return LDAPException.PARAM_ERROR;
2194    }
2195
2196    if (collectingStats)
2197    {
2198      deleteCount.increment();
2199      deleteTimer.startTimer();
2200    }
2201
2202    try
2203    {
2204      conn.delete(dn, constraints);
2205    }
2206    catch (LDAPException le)
2207    {
2208      resultCode = le.getLDAPResultCode();
2209    }
2210
2211    if (collectingStats)
2212    {
2213      deleteTimer.stopTimer();
2214    }
2215
2216    return resultCode;
2217  }
2218
2219
2220
2221  /**
2222   * Performs a modify operation in the directory.
2223   *
2224   * @return The result code of the modify operation.
2225   */

2226  public int doModify()
2227  {
2228    int resultCode = LDAPException.SUCCESS;
2229    String JavaDoc dn = getEntryDN();
2230    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2231    LDAPModification mod = new LDAPModification(LDAPModification.REPLACE,
2232                                                       attr);
2233
2234    if (collectingStats)
2235    {
2236      modifyCount.increment();
2237      modifyTimer.startTimer();
2238    }
2239
2240    try
2241    {
2242      conn.modify(dn, mod);
2243    }
2244    catch (LDAPException le)
2245    {
2246      resultCode = le.getLDAPResultCode();
2247    }
2248
2249    if (collectingStats)
2250    {
2251      modifyTimer.stopTimer();
2252    }
2253
2254    return resultCode;
2255  }
2256
2257
2258
2259  /**
2260   * Performs a modify RDN (i.e., rename) operation in the directory.
2261   *
2262   * @return The result code of the modify RDN operation.
2263   */

2264  public int doModifyRDN()
2265  {
2266    int resultCode = LDAPException.SUCCESS;
2267    String JavaDoc dn = getDNToDelete();
2268    String JavaDoc newRDNValue = getRandomString(80);
2269
2270    if (dn == null)
2271    {
2272      return LDAPException.PARAM_ERROR;
2273    }
2274
2275    if (collectingStats)
2276    {
2277      modifyRDNCount.increment();
2278      modifyRDNTimer.startTimer();
2279    }
2280
2281    try
2282    {
2283
2284      conn.rename(dn, "uid=" + newRDNValue, true, constraints);
2285      addDNToDelete("uid=" + newRDNValue + "," + baseDN);
2286    }
2287    catch (LDAPException le)
2288    {
2289      resultCode = le.getLDAPResultCode();
2290    }
2291
2292    if (collectingStats)
2293    {
2294      modifyRDNTimer.stopTimer();
2295    }
2296
2297    return resultCode;
2298  }
2299
2300
2301
2302  /**
2303   * Performs a search operation in the directory.
2304   *
2305   * @return The result code of the search operation.
2306   */

2307  public int doSearch()
2308  {
2309    int resultCode = LDAPException.SUCCESS;
2310    String JavaDoc filter = getSearchFilter();
2311
2312    if (collectingStats)
2313    {
2314      searchCount.increment();
2315      searchTimer.startTimer();
2316    }
2317
2318    try
2319    {
2320      LDAPSearchResults results = conn.search(baseDN, LDAPConnection.SCOPE_SUB,
2321                                              filter, null, false,
2322                                              searchConstraints);
2323      while (results.hasMoreElements())
2324      {
2325        Object JavaDoc element = results.nextElement();
2326      }
2327    }
2328    catch (LDAPException le)
2329    {
2330      resultCode = le.getLDAPResultCode();
2331    }
2332
2333    if (collectingStats)
2334    {
2335      searchTimer.stopTimer();
2336    }
2337
2338    return resultCode;
2339  }
2340
2341
2342
2343  /**
2344   * Retrieves a randomly-generated entry that may be added to the directory.
2345   *
2346   * @return The generated entry.
2347   */

2348  public LDAPEntry getEntry()
2349  {
2350    String JavaDoc randomString = getRandomString(80);
2351
2352    String JavaDoc[] ocValues = new String JavaDoc[]
2353    { "top",
2354      "person",
2355      "organizationalPerson",
2356      "inetOrgPerson"
2357    };
2358
2359    LDAPAttribute[] attrs = new LDAPAttribute[]
2360    {
2361      new LDAPAttribute("objectClass", ocValues),
2362      new LDAPAttribute("uid", randomString),
2363      new LDAPAttribute("givenName", randomString),
2364      new LDAPAttribute("sn", randomString),
2365      new LDAPAttribute("cn", randomString),
2366      new LDAPAttribute("userPassword", randomString)
2367    };
2368
2369    LDAPAttributeSet attrSet = new LDAPAttributeSet(attrs);
2370
2371    return new LDAPEntry("uid=" + randomString + "," + baseDN, attrSet);
2372  }
2373
2374
2375
2376  /**
2377   * Retrieves a randomly-generated string with the specified number of
2378   * characters.
2379   *
2380   * @param length The number of characters to include in the string.
2381   *
2382   * @return The randomly-generated string.
2383   */

2384  public String JavaDoc getRandomString(int length)
2385  {
2386    char[] returnChars = new char[length];
2387
2388    for (int i=0; i < returnChars.length; i++)
2389    {
2390      returnChars[i] = ALPHABET[(random.nextInt() & 0x7FFFFFFF) %
2391                                ALPHABET.length];
2392    }
2393
2394    return new String JavaDoc(returnChars);
2395  }
2396
2397
2398
2399  /**
2400   * Retrieves the DN of an entry on which a compare or modify operation may be
2401   * performed.
2402   *
2403   * @return The DN of an entry on which a compare or modify operation may be
2404   * performed.
2405   */

2406  public String JavaDoc getEntryDN()
2407  {
2408    if (entryDNs == null)
2409    {
2410      if (useDNRange)
2411      {
2412        int value;
2413
2414        if (useSequentialDNs)
2415        {
2416          value = nextDN++;
2417          if (nextDN > dnMax)
2418          {
2419            nextDN = dnMin;
2420          }
2421        }
2422        else
2423        {
2424          value = ((random.nextInt() & 0x7FFFFFFF) % dnSpan) + dnMin;
2425        }
2426
2427        return dnInitial + value + dnFinal;
2428      }
2429      else
2430      {
2431        return dnInitial;
2432      }
2433    }
2434    else
2435    {
2436      return entryDNs[(random.nextInt() & 0x7FFFFFFF) % entryDNs.length];
2437    }
2438  }
2439
2440
2441
2442  /**
2443   * Adds the specified DN to the list of DNs to be deleted and/or renamed.
2444   *
2445   * @param entryDN The DN to be added to the list.
2446   */

2447  public void addDNToDelete(String JavaDoc entryDN)
2448  {
2449    synchronized (addedDNMutex)
2450    {
2451      dnsToDelete++;
2452      addedDNs.add(entryDN);
2453    }
2454  }
2455
2456
2457
2458  /**
2459   * Retrieves the DN of an entry to be deleted or renamed. Delete and modify
2460   * RDN operations will only be performed on entries that have been added.
2461   *
2462   * @return The DN of an entry that can be deleted or renamed. If there are
2463   * no available DNs, then <CODE>null</CODE> will be returned.
2464   */

2465  public String JavaDoc getDNToDelete()
2466  {
2467    synchronized (addedDNMutex)
2468    {
2469      if (dnsToDelete > 0)
2470      {
2471        dnsToDelete--;
2472        return (String JavaDoc) addedDNs.removeFirst();
2473      }
2474    }
2475
2476    return null;
2477  }
2478
2479
2480
2481  /**
2482   * Retrieves a filter that may be used to perform a search.
2483   *
2484   * @return The filter that may be used to perform a search.
2485   */

2486  public String JavaDoc getSearchFilter()
2487  {
2488    if (searchFilters == null)
2489    {
2490      if (useFilterRange)
2491      {
2492        int value;
2493
2494        if (useSequentialFilters)
2495        {
2496          value = nextFilter++;
2497          if (nextFilter > filterMax)
2498          {
2499            nextFilter = filterMin;
2500          }
2501        }
2502        else
2503        {
2504          value = ((random.nextInt() & 0x7FFFFFFF) % filterSpan) + filterMin;
2505        }
2506
2507        return filterInitial + value + filterFinal;
2508      }
2509      else
2510      {
2511        return filterInitial;
2512      }
2513    }
2514    else
2515    {
2516      return searchFilters[(random.nextInt() & 0x7FFFFFFF) %
2517                           searchFilters.length];
2518    }
2519  }
2520
2521
2522
2523  /**
2524   * Specifies the credentials that will be used to bind to the target server if
2525   * a referral is encountered. In this case, we will always attempt the bind
2526   * using the same credentials used to bind to the original target.
2527   *
2528   * @param host The address of the directory server targeted by the referral.
2529   * @param port The port of the directory server targeted by the referral.
2530   *
2531   * @return The credentials that will be used to bind to the server targeted
2532   * by the referral.
2533   */

2534  public LDAPRebindAuth getRebindAuthentication(String JavaDoc host, int port)
2535  {
2536    return new LDAPRebindAuth(bindDN, bindPW);
2537  }
2538}
2539
2540
Popular Tags