KickJava   Java API By Example, From Geeks To Geeks.

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


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.util.*;
21 import netscape.ldap.*;
22 import com.sun.slamd.job.*;
23 import com.sun.slamd.parameter.*;
24 import com.sun.slamd.stat.*;
25
26
27
28 /**
29  * This class defines a SLAMD job that simulates the load that SiteMinder can
30  * place on an LDAP directory server while measuring latency associated with
31  * replicating the changes it makes. The load that it uses is based on the
32  * following (rather inefficient) sequence of events:
33  *
34  * <OL>
35  * <LI>Perform a subtree search from the directory suffix to find the user's
36  * entry based on a login ID.</LI>
37  * <LI>Perform a base-level search on the user's entry to retrieve the
38  * objectClass attribute.</LI>
39  * <LI>Perform a bind as the user. This is done on a different connection
40  * than all of the other steps.</LI>
41  * <LI>Perform a base-level search on the user's entry to retrieve a given
42  * user-specified attribute (attr1).</LI>
43  * <LI>Perform a base-level search on the user's entry to retrieve a second
44  * user-specified attribute (attr2).</LI>
45  * <LI>Perform a base-level search on the user's entry to retrieve the first
46  * attribute (attr1).</LI>
47  * <LI>Perform a modification on the user's entry.</LI>
48  * <LI>Perform a base-level search on the user's entry to retrieve the first
49  * attribute again.</LI>
50  * <LI>Perform a base-level search on the user's entry to retrieve the first
51  * attribute again.</LI>
52  * <LI>Perform a base-level search on the user's entry to retrieve a third
53  * attribute (attr3).</LI>
54  * </OL>
55  *
56  *
57  * @author Neil A. Wilson
58  */

59 public class SiteMinderWithReplicaLatencyJobClass
60        extends ReplicaLatencyCheckJobClass
61 {
62   /**
63    * The set of characters that will be used to generate random values for the
64    * modifications.
65    */

66   public static final char[] ALPHABET =
67        "abcdefghijklmnopqrstuvwxyz".toCharArray();
68
69
70
71   /**
72    * The default value for the first attribute to retrieve during the
73    * authentication process.
74    */

75   public static final String JavaDoc DEFAULT_ATTR1 = "givenName";
76
77
78
79   /**
80    * The default value for the second attribute to retrieve during the
81    * authentication process.
82    */

83   public static final String JavaDoc DEFAULT_ATTR2 = "sn";
84
85
86
87   /**
88    * The default value for the third attribute to retrieve during the
89    * authentication process.
90    */

91   public static final String JavaDoc DEFAULT_ATTR3= "cn";
92
93
94
95   /**
96    * The default attribute used as the login ID.
97    */

98   public static final String JavaDoc DEFAULT_LOG_ID_ATTR = "uid";
99
100
101
102   /**
103    * The name of the stat tracker that will be used to count the number of
104    * authentication attempts.
105    */

106   public static final String JavaDoc STAT_TRACKER_AUTHENTICATION_ATTEMPTS =
107        "Authentication Attempts";
108
109
110
111
112   /**
113    * The name of the stat tracker that will be used to keep track of the time
114    * required to perform each authentication.
115    */

116   public static final String JavaDoc STAT_TRACKER_AUTHENTICATION_TIME =
117        "Authentication Time (ms)";
118
119
120
121   /**
122    * The name of the stat tracker that will be used to keep track of the time
123    * required to perform each bind.
124    */

125   public static final String JavaDoc STAT_TRACKER_BIND_TIME = "Bind Time (ms)";
126
127
128
129
130   /**
131    * The name of the stat tracker that will be used to count the number of
132    * failed authentications.
133    */

134   public static final String JavaDoc STAT_TRACKER_FAILED_AUTHENTICATIONS =
135        "Failed Authentications";
136
137
138
139   /**
140    * The name of the stat tracker that will be used to categorize the reasons
141    * for the failed auths.
142    */

143   public static final String JavaDoc STAT_TRACKER_FAIL_REASON = "Failure Reason";
144
145
146
147   /**
148    * The name of the stat tracker that will be used to keep track of the time
149    * required to perform the initial search (to find the user's entry).
150    */

151   public static final String JavaDoc STAT_TRACKER_INITIAL_SEARCH_TIME =
152        "Initial Search Time (ms)";
153
154
155
156   /**
157    * The name of the stat tracker that will be used to keep track of the time
158    * required to perform each modification.
159    */

160   public static final String JavaDoc STAT_TRACKER_MOD_TIME = "Modify Time (ms)";
161
162
163
164   /**
165    * The name of the stat tracker that will be used to keep track of the number
166    * of bind operations performed.
167    */

168   public static final String JavaDoc STAT_TRACKER_NUM_BINDS =
169        "Bind Operations Performed";
170
171
172
173   /**
174    * The name of the stat tracker that will be used to keep track of the number
175    * of modify operations performed.
176    */

177   public static final String JavaDoc STAT_TRACKER_NUM_MODS =
178        "Modify Operations Performed";
179
180
181
182   /**
183    * The name of the stat tracker that will be used to keep track of the number
184    * of search operations performed.
185    */

186   public static final String JavaDoc STAT_TRACKER_NUM_SEARCH =
187        "Search Operations Performed";
188
189
190
191   /**
192    * The name of the stat tracker that will be used to keep track of the time
193    * required to perform subsequent searches (to retrieve specific attributes
194    * from the user's entry).
195    */

196   public static final String JavaDoc STAT_TRACKER_SUBSEQUENT_SEARCH_TIME =
197        "Subsequent Search Time (ms)";
198
199
200
201   /**
202    * The name of the stat tracker that will be used to count the number of
203    * successful authentications.
204    */

205   public static final String JavaDoc STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS =
206        "Successful Authentications";
207
208
209
210   /**
211    * The name of the stat tracker that will be used to track replication
212    * latency.
213    */

214   public static final String JavaDoc STAT_TRACKER_REPLICATION_LATENCY =
215        "Replication Latency (ms)";
216
217
218
219   /**
220    * The name of the stat tracker that will be used to categorize latency.
221    */

222   public static final String JavaDoc STAT_TRACKER_CATEGORIZED_LATENCY =
223        "Categorized Latency";
224
225
226
227   /**
228    * The default set of attributes to include in the modification.
229    */

230   public static final String JavaDoc[] DEFAULT_ATTRS_TO_MODIFY = new String JavaDoc[]
231   {
232     "description"
233   };
234
235
236
237   // Indicates whether bind failures because of invalid credentials will be
238
// ignored (so you don't actually have to know user passwords).
239
static boolean ignoreInvalidCredentials;
240
241   // Indicates whether a thread has been chosen to manage latency checking.
242
static boolean latencyTrackerChosen;
243
244   // Indicates whether the bind should be attempted or skipped.
245
static boolean skipBind;
246
247   // Indicates whether login IDs/passwords are read from a data file or from
248
// parameters.
249
static boolean useDataFile;
250
251   // Indicates whether the login ID value should be interpreted as a range.
252
static boolean useLoginIDRange;
253
254   // Indicates whether the login ID value should increment sequentially.
255
static boolean useSequential;
256
257   // Indicates whether all threads will used a shared set of connections or if
258
// each thread will have its own connection.
259
static boolean useSharedConnections;
260
261   // The time to keep working after stopping statistics collection.
262
static int coolDownTime;
263
264   // The length of time in milliseconds to allow between latency checks.
265
static int latencyDelay;
266
267   // The maximum value to use in the range of login IDs.
268
static int loginIDMax;
269
270   // The minimum value to use in the range of login IDs.
271
static int loginIDMin;
272
273   // The maximum value to use in the range of login IDs.
274
static int loginIDSpan;
275
276   // The port number of the master directory server.
277
static int masterPort;
278
279   // The port number of the replica directory server.
280
static int replicaPort;
281
282   // The next sequential value that should be used in the login ID value.
283
static int sequentialCounter;
284
285   // The maximum length of time that any single LDAP operation will be allowed
286
// to take before it is cancelled.
287
static int timeLimit;
288
289   // The time to start working before beginning statistics collection.
290
static int warmUpTime;
291
292   // The delay in milliseconds between authentication attempts.
293
static long delay;
294
295   // The LDAP connection that will be used for shared authentication operations.
296
static LDAPConnection sharedAuthConnection;
297
298   // The LDAP connection that will be used for shared bind operations.
299
static LDAPConnection sharedBindConnection;
300
301   // The random number generator that will seed the thread-specific random
302
// number generators.
303
static Random parentRandom;
304
305   // The DN to use to bind to the directory when performing the search and
306
// modify operations.
307
static String JavaDoc bindDN;
308
309   // The password for the bind DN.
310
static String JavaDoc bindPW;
311
312   // The search filter to use when searching on the first attribute.
313
static String JavaDoc filter1;
314
315   // The search filter to use when searching on the second attribute.
316
static String JavaDoc filter2;
317
318   // The search filter to use when searching on the third attribute.
319
static String JavaDoc filter3;
320
321   // The name of the attribute that will be used to initially find the user's
322
// entry (the login ID attribute).
323
static String JavaDoc loginIDAttr;
324
325   // The text to include after the numeric part of the login ID.
326
static String JavaDoc loginIDFinal;
327
328   // The text to include before the numeric part of the login ID.
329
static String JavaDoc loginIDInitial;
330
331   // The password to use when authenticating.
332
static String JavaDoc loginPassword;
333
334   // The address of the master directory server.
335
static String JavaDoc masterHost;
336
337   // The DN of the entry to use for latency checking.
338
static String JavaDoc replicaEntryDN;
339
340   // The address of the replica directory server.
341
static String JavaDoc replicaHost;
342
343   // The name of the first attribute to retrieve.
344
static String JavaDoc searchAttr1;
345
346   // The name of the second attribute to retrieve.
347
static String JavaDoc searchAttr2;
348
349   // The name of the third attribute to retrieve.
350
static String JavaDoc searchAttr3;
351
352   // The DN to use as the search base when trying to find user entries in the
353
// directory.
354
static String JavaDoc searchBase;
355
356   // The set of login IDs that will be used to authenticate.
357
static String JavaDoc[] loginIDs;
358
359   // The set of passwords associated with the login IDs.
360
static String JavaDoc[] loginPasswords;
361
362   // The names of the attributes to alter in the modification.
363
static String JavaDoc[] modAttrs;
364
365   // The set of attributes to return when retrieving the first attribute.
366
static String JavaDoc[] returnAttrs1;
367
368   // The set of attributes to return when retrieving the second attribute.
369
static String JavaDoc[] returnAttrs2;
370
371   // The set of attributes to return when retrieving the third attribute.
372
static String JavaDoc[] returnAttrs3;
373
374   // The set of attributes to return when retrieving the set of objectclasses.
375
static String JavaDoc[] returnAttrsOC;
376
377
378
379   // The parameter used to indicate whether invalid credential results are
380
// ignored.
381
BooleanParameter ignoreInvCredParameter =
382        new BooleanParameter("ignore_49", "Ignore Invalid Credentials Errors",
383                             "Indicates whether bind failures because of " +
384                             "invalid credentials (err=49). This makes it " +
385                             "possible to use this job without actually " +
386                             "know user passwords.", false);
387
388   // The parameter used to indicate whether connections are shared.
389
BooleanParameter shareConnsParameter =
390        new BooleanParameter("share_conns", "Share Connections between Threads",
391                             "Indicates whether the connections to the " +
392                             "directory server will be shared between threads " +
393                             "or if each client thread will have its own " +
394                             "connections.", true);
395
396   // The parameter used to indicate whether to skip the bind operation.
397
BooleanParameter skipBindParameter =
398        new BooleanParameter("skip_bind", "Skip Bind Operation",
399                             "Indicates whether the bind attempt should be " +
400                             "skipped as part of the authentication process.",
401                             false);
402
403   // The parameter used to indicate the login ID/password file.
404
FileURLParameter loginDataFileParameter =
405        new FileURLParameter("login_data_file", "Login Data File URL",
406                             "The URL (FILE or HTTP) of the file containing " +
407                             "the login IDs and passwords to use for the " +
408                             "authentication.", null, false);
409
410   // The parmeter that specifies the cool-down time in seconds.
411
IntegerParameter coolDownParameter =
412        new IntegerParameter("cool_down", "Cool Down Time",
413                             "The time in seconds that the job should " +
414                             "continue searching after ending statistics " +
415                             "collection.", true, 0, true, 0, false, 0);
416
417   // The parameter that indicates the delay that should be used between each
418
// authentication attempt.
419
IntegerParameter delayParameter =
420        new IntegerParameter("delay", "Time Between Authentications (ms)",
421                             "Specifies the length of time in milliseconds " +
422                             "each thread should wait between authentication " +
423                             "attempts. Note that this delay will be " +
424                             "between the starts of consecutive attempts and " +
425                             "not between the end of one attempt and the " +
426                             "beginning of the next. If an authentication " +
427                             "takes longer than this length of time, then " +
428                             "there will be no delay.", true, 0, true, 0, false,
429                             0);
430
431   // The parameter that indicates the minimum length of time to sleep between
432
// modifications of the latency check entry.
433
IntegerParameter replicaDelayParameter =
434        new IntegerParameter("latency_delay", "Time Between Latency Checks (ms)",
435                             "Specifies the minimum length of time in " +
436                             "milliseconds that should pass between latency " +
437                             "checks. If a replicated operation takes longer " +
438                             "than this length of time, then there will be no " +
439                             "delay.", true, 0, true, 0, false, 0);
440
441   // The parameter that indicates the port number for the master directory.
442
IntegerParameter masterPortParameter =
443        new IntegerParameter("master_port", "Master Directory Port",
444                             "The port number for the master directory server",
445                             true, 389, true, 1, true, 65535);
446
447   // The parameter that indicates the port number for the replica directory.
448
IntegerParameter replicaPortParameter =
449        new IntegerParameter("replica_port", "Replica Directory Port",
450                             "The port number for the replica directory server",
451                             true, 389, true, 1, true, 65535);
452
453   // The parameter used to indicate the maximum length of time that any single
454
// LDAP operation will be allowed to take.
455
IntegerParameter timeLimitParameter =
456        new IntegerParameter("time_limit", "Operation Time Limit",
457                             "The maximum length of time in seconds that any " +
458                             "single LDAP operation will be allowed to take " +
459                             "before it is cancelled.", true, 0, true, 0, false,
460                             0);
461
462   // The parmeter that specifies the cool-down time in seconds.
463
IntegerParameter warmUpParameter =
464        new IntegerParameter("warm_up", "Warm Up Time",
465                             "The time in seconds that the job should " +
466                             "search before beginning statistics collection.",
467                             true, 0, true, 0, false, 0);
468
469   // The parameter used to indicate the attributes to modify.
470
MultiLineTextParameter modAttrsParameter =
471        new MultiLineTextParameter("mod_attrs", "Attributes to Modify",
472                                   "The set of attributes to modify.",
473                                   DEFAULT_ATTRS_TO_MODIFY, false);
474
475   // The parameter used to indicate the password for the bind DN.
476
PasswordParameter bindPWParameter =
477        new PasswordParameter("bindpw", "Directory Bind Password",
478                              "The password to use when binding to the " +
479                              "directory server to perform search and modify " +
480                              "operations.", false, "");
481
482   // The parameter used to indicate the password to use when authenticating to
483
// the directory.
484
PasswordParameter loginPasswordParameter =
485        new PasswordParameter("login_id_pw", "Login Password",
486                              "The password to use when authenticating to the " +
487                              "directory for user authentications.", false, "");
488
489   // The placeholder parameter used as a spacer in the admin interface.
490
PlaceholderParameter placeholder = new PlaceholderParameter();
491
492   // The parameter used to indicate the first attribute to retrieve.
493
StringParameter attr1Parameter =
494        new StringParameter("attr1", "First Attribute to Retrieve",
495                            "The first attribute to retrieve from the user's " +
496                            "entry as part of the authentication process.",
497                            true, DEFAULT_ATTR1);
498
499   // The parameter used to indicate the first attribute to retrieve.
500
StringParameter attr2Parameter =
501        new StringParameter("attr2", "Second Attribute to Retrieve",
502                            "The second attribute to retrieve from the user's " +
503                            "entry as part of the authentication process.",
504                            true, DEFAULT_ATTR2);
505
506   // The parameter used to indicate the first attribute to retrieve.
507
StringParameter attr3Parameter =
508        new StringParameter("attr3", "Third Attribute to Retrieve",
509                            "The third attribute to retrieve from the user's " +
510                            "entry as part of the authentication process.",
511                            true, DEFAULT_ATTR3);
512
513   // The parameter used to indicate the bind DN.
514
StringParameter bindDNParameter =
515        new StringParameter("binddn", "Directory Bind DN",
516                            "The DN to use when binding to the directory " +
517                            "server to perform search and modify operations.",
518                            false, "");
519
520   // The parameter used to indicate the attribute to use for the login ID.
521
StringParameter loginIDParameter =
522        new StringParameter("login_id_attr", "Login ID Attribute",
523                            "The attribute to use as the login ID to find the " +
524                            "user's entry.", true, DEFAULT_LOG_ID_ATTR);
525
526   // The parameter used to indicate the login ID value or value pattern.
527
StringParameter loginIDValueParameter =
528        new StringParameter("login_id_value", "Login ID Value",
529                            "The text to use as the value of the login ID " +
530                            "attribute in search filters. The value may " +
531                            "contain a range of numbers in square brackets.",
532                            false, "");
533
534   // The parameter that indicates the address of the master directory server
535
StringParameter masterHostParameter =
536        new StringParameter("masterhost", "Master Directory Host",
537                            "The DNS hostname or IP address of the master " +
538                            "directory server", true, "");
539
540   // The parameter that specifies the DN of the entry to watch for replication
541
// latency.
542
StringParameter replicaEntryDNParameter =
543        new StringParameter("replica_entrydn", "Latency Check Entry DN",
544                            "The DN of the entry that should be periodically " +
545                            "modified to measure the latency of replication. " +
546                            "Note that this DN must not be the same as " +
547                            "the DN of any of the entries to modify, nor " +
548                            "should this entry be modified by any external " +
549                            "process during the test.", true, "");
550
551   // The parameter that indicates the address of the replica directory server
552
StringParameter replicaHostParameter =
553        new StringParameter("replicahost", "Replica Directory Host",
554                            "The DNS hostname or IP address of the replica " +
555                            "directory server", true, "");
556
557   // The parameter used to indicate the search base for the directory.
558
StringParameter searchBaseParameter =
559     new StringParameter("search_base", "User Search Base",
560                         "The DN in the directory server under which user " +
561                         "entries may be found.", true, "");
562
563
564   // Indicates whether this thread should report latency statistics.
565
boolean reportLatencyTracker;
566
567   // The stat tracker that will categorize the reasons for auth failures.
568
CategoricalTracker failureReasonTracker;
569
570   // The stat tracker that will count the number of authentication attempts.
571
IncrementalTracker attemptCounter;
572
573   // The stat tracker that will count the number of binds performed.
574
IncrementalTracker bindCounter;
575
576   // The stat tracker that will count the number of failed authentications.
577
IncrementalTracker failureCounter;
578
579   // The stat tracker that will count the number of modify operations performed.
580
IncrementalTracker modCounter;
581
582   // The stat tracker that will count the number of searches performed.
583
IncrementalTracker searchCounter;
584
585   // The stat tracker that will count the number of successful authentications.
586
IncrementalTracker successCounter;
587
588   // The thread used for performing changes on the master server.
589
LatencyCheckMasterThread masterThread;
590
591   // The thread used for detecting changes on the replica server.
592
LatencyCheckReplicaThread replicaThread;
593
594   // The LDAP connection that will be used for authentication operations by this
595
// thread.
596
LDAPConnection authConnection;
597
598   // The LDAP connection that will be used for bind operations by this thread.
599
LDAPConnection bindConnection;
600
601   // The set of constraints that will be used for non-search/bind operations.
602
LDAPConstraints authConstraints;
603
604   // The set of constraints that will be used for bind operations.
605
LDAPConstraints bindConstraints;
606
607   // The set of constraints that will be used for search operations.
608
LDAPSearchConstraints authSearchConstraints;
609
610   // The random number generator for this thread.
611
Random random;
612
613   // The stat tracker that will time each authentication.
614
TimeTracker authTimer;
615
616   // The stat tracker that will time each bind attempt.
617
TimeTracker bindTimer;
618
619   // The stat tracker that will time the initial search to find the user's
620
// entry.
621
TimeTracker initialSearchTimer;
622
623   // The stat tracker that will time each modify attempt.
624
TimeTracker modTimer;
625
626   // The stat tracker that will time each search to retrieve specific attributes
627
// from the user's entry.
628
TimeTracker subsequentSearchTimer;
629
630
631
632   /**
633    * Creates a new instance of this job thread. This constructor does not need
634    * to do anything other than invoke the constructor for the superclass.
635    */

636   public SiteMinderWithReplicaLatencyJobClass()
637   {
638     super();
639   }
640
641
642
643   /**
644    * Returns the user-friendly name that is to be used for this job class in the
645    * administrative interface.
646    *
647    * @return The user-friendly name for this job class.
648    */

649   public String JavaDoc getJobName()
650   {
651     return "LDAP SiteMinder Load Simulator with Replication Latency";
652   }
653
654
655
656   /**
657    * Returns a description of this job that can be seen in the administrative
658    * interface.
659    *
660    * @return A description of this job class.
661    */

662   public String JavaDoc getJobDescription()
663   {
664     return "This job simulates the load that SiteMinder can place on the " +
665            "directory server when it is performing authentications. It also " +
666            "measures the replication latency for changes performed as part " +
667            "of the authentication.";
668   }
669
670
671
672   /**
673    * Retrieves the name of the category in which this job class exists. This is
674    * used to help arrange the job classes in the administrative interface.
675    *
676    * @return The name of the category in which this job class exists.
677    */

678   public String JavaDoc getJobCategoryName()
679   {
680     return "LDAP";
681   }
682
683
684
685   /**
686    * Returns the set of parameters whose value may be specified by the end user.
687    *
688    * @return The set of configurable parameters for this job class.
689    */

690   public ParameterList getParameterStubs()
691   {
692     Parameter[] parameterArray = new Parameter[]
693     {
694       placeholder,
695       masterHostParameter,
696       masterPortParameter,
697       bindDNParameter,
698       bindPWParameter,
699       placeholder,
700       replicaHostParameter,
701       replicaPortParameter,
702       replicaEntryDNParameter,
703       replicaDelayParameter,
704       placeholder,
705       searchBaseParameter,
706       loginDataFileParameter,
707       loginIDValueParameter,
708       loginPasswordParameter,
709       loginIDParameter,
710       placeholder,
711       attr1Parameter,
712       attr2Parameter,
713       attr3Parameter,
714       modAttrsParameter,
715       placeholder,
716       warmUpParameter,
717       coolDownParameter,
718       timeLimitParameter,
719       delayParameter,
720       placeholder,
721       skipBindParameter,
722       ignoreInvCredParameter,
723       shareConnsParameter
724     };
725
726     return new ParameterList(parameterArray);
727   }
728
729
730
731   /**
732    * Retrieves the set of stat trackers that will be maintained by this job
733    * class. The stat trackers returned by this method do not have to actually
734    * contain any statistics -- the display name and stat tracker class should
735    * be the only information that callers of this method should rely upon. Note
736    * that this list can be different from the list of statistics actually
737    * collected by the job in some cases (e.g., if the job may not return all the
738    * stat trackers it advertises in all cases, or if the job may return stat
739    * trackers that it did not advertise), but it is a possibility that only the
740    * stat trackers returned by this method will be accessible for some features
741    * in the SLAMD server.
742    *
743    * @param clientID The client ID that should be used for the
744    * returned stat trackers.
745    * @param threadID The thread ID that should be used for the
746    * returned stat trackers.
747    * @param collectionInterval The collection interval that should be used for
748    * the returned stat trackers.
749    *
750    * @return The set of stat trackers that will be maintained by this job
751    * class.
752    */

753   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
754                                            int collectionInterval)
755   {
756     return new StatTracker[]
757     {
758       new IncrementalTracker(clientID, threadID,
759                              STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
760                              collectionInterval),
761       new IncrementalTracker(clientID, threadID,
762                              STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
763                              collectionInterval),
764       new IncrementalTracker(clientID, threadID,
765                              STAT_TRACKER_FAILED_AUTHENTICATIONS,
766                              collectionInterval),
767       new TimeTracker(clientID, threadID, STAT_TRACKER_AUTHENTICATION_TIME,
768                       collectionInterval),
769       new IncrementalTracker(clientID, threadID, STAT_TRACKER_NUM_BINDS,
770                              collectionInterval),
771       new TimeTracker(clientID, threadID, STAT_TRACKER_BIND_TIME,
772                       collectionInterval),
773       new IncrementalTracker(clientID, threadID, STAT_TRACKER_NUM_MODS,
774                              collectionInterval),
775       new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_TIME,
776                       collectionInterval),
777       new IncrementalTracker(clientID, threadID, STAT_TRACKER_NUM_SEARCH,
778                              collectionInterval),
779       new TimeTracker(clientID, threadID, STAT_TRACKER_INITIAL_SEARCH_TIME,
780                       collectionInterval),
781       new TimeTracker(clientID, threadID, STAT_TRACKER_SUBSEQUENT_SEARCH_TIME,
782                       collectionInterval),
783       new CategoricalTracker(clientID, threadID, STAT_TRACKER_FAIL_REASON,
784                              collectionInterval),
785       new TimeTracker(clientID, threadID, STAT_TRACKER_REPLICATION_LATENCY,
786                       collectionInterval),
787       new CategoricalTracker(clientID, threadID,
788                              STAT_TRACKER_CATEGORIZED_LATENCY,
789                              collectionInterval)
790     };
791   }
792
793
794
795   /**
796    * Retrieves the set of stat trackers that are maintained by this job class.
797    *
798    * @return The set of stat trackers for this job class.
799    */

800   public StatTracker[] getStatTrackers()
801   {
802     if (reportLatencyTracker)
803     {
804       return new StatTracker[]
805       {
806         attemptCounter,
807         successCounter,
808         failureCounter,
809         authTimer,
810         bindCounter,
811         bindTimer,
812         modCounter,
813         modTimer,
814         searchCounter,
815         initialSearchTimer,
816         subsequentSearchTimer,
817         failureReasonTracker,
818         latencyTime,
819         latencyCategories
820       };
821     }
822     else
823     {
824       return new StatTracker[]
825       {
826         attemptCounter,
827         successCounter,
828         failureCounter,
829         authTimer,
830         bindCounter,
831         bindTimer,
832         modCounter,
833         modTimer,
834         searchCounter,
835         initialSearchTimer,
836         subsequentSearchTimer,
837         failureReasonTracker
838       };
839     }
840   }
841
842
843
844   /**
845    * Provides a means of validating the information used to schedule the job,
846    * including the scheduling information and list of parameters.
847    *
848    * @param numClients The number of clients that should be used to
849    * run the job.
850    * @param threadsPerClient The number of threads that should be created on
851    * each client to run the job.
852    * @param threadStartupDelay The delay in milliseconds that should be used
853    * when starting the client threads.
854    * @param startTime The time that the job should start running.
855    * @param stopTime The time that the job should stop running.
856    * @param duration The maximum length of time in seconds that the
857    * job should be allowed to run.
858    * @param collectionInterval The collection interval that should be used
859    * when gathering statistics for the job.
860    * @param parameters The set of parameters provided to this job that
861    * can be used to customize its behavior.
862    *
863    * @throws InvalidValueException If the provided information is not
864    * appropriate for running this job.
865    */

866   public void validateJobInfo(int numClients, int threadsPerClient,
867                               int threadStartupDelay, Date startTime,
868                               Date stopTime, int duration,
869                               int collectionInterval, ParameterList parameters)
870          throws InvalidValueException
871   {
872     FileURLParameter loginDataURLParameter =
873          parameters.getFileURLParameter(loginDataFileParameter.getName());
874     if ((loginDataURLParameter == null) ||
875         (! loginDataURLParameter.hasValue()))
876     {
877       StringParameter loginValueParameter =
878            parameters.getStringParameter(loginIDValueParameter.getName());
879       PasswordParameter loginPWParameter =
880            parameters.getPasswordParameter(loginPasswordParameter.getName());
881
882       if ((loginValueParameter == null) ||
883           (! loginValueParameter.hasValue()) ||
884           (loginPWParameter == null) ||
885           (! loginPWParameter.hasValue()))
886       {
887         throw new InvalidValueException("You must specify either a login " +
888                                         "data file URL or a login ID value " +
889                                         "and password");
890       }
891     }
892   }
893
894
895
896   /**
897    * Indicates whether this job class implements logic that makes it possible to
898    * test the validity of job parameters before scheduling the job for execution
899    * (e.g., to see if the server is reachable using the information provided).
900    *
901    * @return <CODE>true</CODE> if this job provides a means of testing the job
902    * parameters, or <CODE>false</CODE> if not.
903    */

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

938   public boolean testJobParameters(ParameterList parameters,
939                                    ArrayList outputMessages)
940   {
941     // Get all the parameters that we might need to perform the test.
942
StringParameter masterHostParam =
943          parameters.getStringParameter(masterHostParameter.getName());
944     if ((masterHostParam == null) || (! masterHostParam.hasValue()))
945     {
946       outputMessages.add("ERROR: No master directory server address was " +
947                          "provided.");
948       return false;
949     }
950     String JavaDoc masterHost = masterHostParam.getStringValue();
951
952
953     IntegerParameter masterPortParam =
954          parameters.getIntegerParameter(masterPortParameter.getName());
955     if ((masterPortParam == null) || (! masterPortParam.hasValue()))
956     {
957       outputMessages.add("ERROR: No master directory server port was " +
958                          "provided.");
959       return false;
960     }
961     int masterPort = masterPortParam.getIntValue();
962
963
964     StringParameter replicaHostParam =
965          parameters.getStringParameter(replicaHostParameter.getName());
966     if ((replicaHostParam == null) || (! replicaHostParam.hasValue()))
967     {
968       outputMessages.add("ERROR: No replica directory server address was " +
969                          "provided.");
970       return false;
971     }
972     String JavaDoc replicaHost = replicaHostParam.getStringValue();
973
974
975     IntegerParameter replicaPortParam =
976          parameters.getIntegerParameter(replicaPortParameter.getName());
977     if ((replicaPortParam == null) || (! replicaPortParam.hasValue()))
978     {
979       outputMessages.add("ERROR: No replica directory server port was " +
980                          "provided.");
981       return false;
982     }
983     int replicaPort = replicaPortParam.getIntValue();
984
985
986     String JavaDoc bindDN = "";
987     StringParameter bindDNParam =
988          parameters.getStringParameter(bindDNParameter.getName());
989     if ((bindDNParam != null) && bindDNParam.hasValue())
990     {
991       bindDN = bindDNParam.getStringValue();
992     }
993
994
995     String JavaDoc bindPassword = "";
996     PasswordParameter bindPWParam =
997          parameters.getPasswordParameter(bindPWParameter.getName());
998     if ((bindPWParam != null) && bindPWParam.hasValue())
999     {
1000      bindPassword = bindPWParam.getStringValue();
1001    }
1002
1003
1004    StringParameter baseDNParam =
1005         parameters.getStringParameter(searchBaseParameter.getName());
1006    if ((baseDNParam == null) || (! baseDNParam.hasValue()))
1007    {
1008      outputMessages.add("ERROR: No base DN was provided.");
1009      return false;
1010    }
1011    String JavaDoc baseDN = baseDNParam.getStringValue();
1012
1013
1014    StringParameter replicaEntryDNParam =
1015         parameters.getStringParameter(replicaEntryDNParameter.getName());
1016    if ((replicaEntryDNParam == null) || (! replicaEntryDNParam.hasValue()))
1017    {
1018      outputMessages.add("ERROR: No replica check entry DN was provided.");
1019      return false;
1020    }
1021    String JavaDoc replicaEntryDN = replicaEntryDNParam.getStringValue();
1022
1023
1024    // Create the LDAPConnection object that we will use to communicate with the
1025
// directory server.
1026
LDAPConnection conn = new LDAPConnection();
1027
1028
1029    // Attempt to establish a connection to the master server.
1030
try
1031    {
1032      outputMessages.add("Attempting to establish a connection to master " +
1033                         masterHost + ":" + masterPort + "....");
1034      conn.connect(masterHost, masterPort);
1035      outputMessages.add("Connected successfully.");
1036      outputMessages.add("");
1037    }
1038    catch (Exception JavaDoc e)
1039    {
1040      outputMessages.add("ERROR: Unable to connect to the master server: " +
1041                         stackTraceToString(e));
1042      return false;
1043    }
1044
1045
1046    // Attempt to bind to the master server using the bind DN and password.
1047
try
1048    {
1049      outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
1050                         "master server with a DN of '" + bindDN + "'....");
1051      conn.bind(3, bindDN, bindPassword);
1052      outputMessages.add("Bound successfully.");
1053      outputMessages.add("");
1054    }
1055    catch (Exception JavaDoc e)
1056    {
1057      try
1058      {
1059        conn.disconnect();
1060      } catch (Exception JavaDoc e2) {}
1061
1062      outputMessages.add("ERROR: Unable to bind to the master server: " +
1063                         stackTraceToString(e));
1064      return false;
1065    }
1066
1067
1068    // Make sure that the entry specified as the base DN exists.
1069
try
1070    {
1071      outputMessages.add("Checking to make sure that the base DN entry '" +
1072                         baseDN + "' exists in the master....");
1073      LDAPEntry baseDNEntry = conn.read(baseDN, new String JavaDoc[] { "1.1" });
1074      if (baseDNEntry == null)
1075      {
1076        try
1077        {
1078          conn.disconnect();
1079        } catch (Exception JavaDoc e2) {}
1080
1081        outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
1082        return false;
1083      }
1084      else
1085      {
1086        outputMessages.add("Successfully read the base DN entry.");
1087        outputMessages.add("");
1088      }
1089    }
1090    catch (Exception JavaDoc e)
1091    {
1092      try
1093      {
1094        conn.disconnect();
1095      } catch (Exception JavaDoc e2) {}
1096
1097      outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
1098                         stackTraceToString(e));
1099      return false;
1100    }
1101
1102
1103    // Make sure that the entry specified as the replica check entry exists.
1104
try
1105    {
1106      outputMessages.add("Checking to make sure that the replica check " +
1107                         "entry '" + replicaEntryDN +
1108                         "' exists in the master....");
1109      LDAPEntry baseDNEntry = conn.read(replicaEntryDN, new String JavaDoc[] { "1.1" });
1110      if (baseDNEntry == null)
1111      {
1112        try
1113        {
1114          conn.disconnect();
1115        } catch (Exception JavaDoc e2) {}
1116
1117        outputMessages.add("ERROR: Unable to retrieve the replica check " +
1118                           "entry.");
1119        return false;
1120      }
1121      else
1122      {
1123        outputMessages.add("Successfully read the replica check entry.");
1124        outputMessages.add("");
1125      }
1126    }
1127    catch (Exception JavaDoc e)
1128    {
1129      try
1130      {
1131        conn.disconnect();
1132      } catch (Exception JavaDoc e2) {}
1133
1134      outputMessages.add("ERROR: Unable to retrieve the replica check " +
1135                         "entry: " + stackTraceToString(e));
1136      return false;
1137    }
1138
1139
1140    // At this point, all tests on the master have passed. Close the connection
1141
// and prepare to start on the replica.
1142
try
1143    {
1144      conn.disconnect();
1145    } catch (Exception JavaDoc e) {}
1146
1147
1148    // Attempt to establish a connection to the replica server.
1149
try
1150    {
1151      outputMessages.add("Attempting to establish a connection to replica " +
1152                         replicaHost + ":" + replicaPort + "....");
1153      conn.connect(replicaHost, replicaPort);
1154      outputMessages.add("Connected successfully.");
1155      outputMessages.add("");
1156    }
1157    catch (Exception JavaDoc e)
1158    {
1159      outputMessages.add("ERROR: Unable to connect to the replica server: " +
1160                         stackTraceToString(e));
1161      return false;
1162    }
1163
1164
1165    // Attempt to bind to the replica server using the bind DN and password.
1166
try
1167    {
1168      outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
1169                         "replica server with a DN of '" + bindDN + "'....");
1170      conn.bind(3, bindDN, bindPassword);
1171      outputMessages.add("Bound successfully.");
1172      outputMessages.add("");
1173    }
1174    catch (Exception JavaDoc e)
1175    {
1176      try
1177      {
1178        conn.disconnect();
1179      } catch (Exception JavaDoc e2) {}
1180
1181      outputMessages.add("ERROR: Unable to bind to the replica server: " +
1182                         stackTraceToString(e));
1183      return false;
1184    }
1185
1186
1187    // Make sure that the entry specified as the base DN exists.
1188
try
1189    {
1190      outputMessages.add("Checking to make sure that the base DN entry '" +
1191                         baseDN + "' exists in the replica....");
1192      LDAPEntry baseDNEntry = conn.read(baseDN, new String JavaDoc[] { "1.1" });
1193      if (baseDNEntry == null)
1194      {
1195        try
1196        {
1197          conn.disconnect();
1198        } catch (Exception JavaDoc e2) {}
1199
1200        outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
1201        return false;
1202      }
1203      else
1204      {
1205        outputMessages.add("Successfully read the base DN entry.");
1206        outputMessages.add("");
1207      }
1208    }
1209    catch (Exception JavaDoc e)
1210    {
1211      try
1212      {
1213        conn.disconnect();
1214      } catch (Exception JavaDoc e2) {}
1215
1216      outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
1217                         stackTraceToString(e));
1218      return false;
1219    }
1220
1221
1222    // Make sure that the entry specified as the replica check entry exists.
1223
try
1224    {
1225      outputMessages.add("Checking to make sure that the replica check " +
1226                         "entry '" + replicaEntryDN +
1227                         "' exists in the replica....");
1228      LDAPEntry baseDNEntry = conn.read(replicaEntryDN, new String JavaDoc[] { "1.1" });
1229      if (baseDNEntry == null)
1230      {
1231        try
1232        {
1233          conn.disconnect();
1234        } catch (Exception JavaDoc e2) {}
1235
1236        outputMessages.add("ERROR: Unable to retrieve the replica check " +
1237                           "entry.");
1238        return false;
1239      }
1240      else
1241      {
1242        outputMessages.add("Successfully read the replica check entry.");
1243        outputMessages.add("");
1244      }
1245    }
1246    catch (Exception JavaDoc e)
1247    {
1248      try
1249      {
1250        conn.disconnect();
1251      } catch (Exception JavaDoc e2) {}
1252
1253      outputMessages.add("ERROR: Unable to retrieve the replica check " +
1254                         "entry: " + stackTraceToString(e));
1255      return false;
1256    }
1257
1258
1259    // At this point, all tests on the replica have passed. Close the
1260
// connection and return true.
1261
try
1262    {
1263      conn.disconnect();
1264    } catch (Exception JavaDoc e) {}
1265
1266
1267    outputMessages.add("All tests completed successfully.");
1268    return true;
1269  }
1270
1271
1272
1273  /**
1274   * Performs initialization for this job on each client immediately before each
1275   * thread is created to actually run the job.
1276   *
1277   * @param clientID The ID assigned to the client running this job.
1278   * @param parameters The set of parameters provided to this job that can be
1279   * used to customize its behavior.
1280   *
1281   * @throws UnableToRunException If the client initialization could not be
1282   * completed successfully and the job is unable
1283   * to run.
1284   */

1285  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1286         throws UnableToRunException
1287  {
1288    // Indicate that no latency tracker thread has yet been chosen.
1289
latencyTrackerChosen = false;
1290
1291
1292    // Get the master directory server address
1293
masterHostParameter =
1294         parameters.getStringParameter(masterHostParameter.getName());
1295    if (masterHostParameter == null)
1296    {
1297      throw new UnableToRunException("No master directory server host " +
1298                                     "provided.");
1299    }
1300    else
1301    {
1302      masterHost = masterHostParameter.getStringValue();
1303    }
1304
1305
1306    // Get the master server port
1307
masterPortParameter =
1308         parameters.getIntegerParameter(masterPortParameter.getName());
1309    if (masterPortParameter != null)
1310    {
1311      masterPort = masterPortParameter.getIntValue();
1312    }
1313
1314
1315    // Get the address of the replica directory server
1316
replicaHost = null;
1317    replicaHostParameter =
1318         parameters.getStringParameter(replicaHostParameter.getName());
1319    if (replicaHostParameter != null)
1320    {
1321      replicaHost = replicaHostParameter.getStringValue();
1322    }
1323
1324
1325    // Get the port for the replica directory server
1326
replicaPort = 389;
1327    replicaPortParameter =
1328         parameters.getIntegerParameter(replicaPortParameter.getName());
1329    if (replicaPortParameter != null)
1330    {
1331      replicaPort = replicaPortParameter.getIntValue();
1332    }
1333
1334
1335    // Get the DN of the entry to use in the latency checks.
1336
replicaEntryDN = null;
1337    replicaEntryDNParameter =
1338         parameters.getStringParameter(replicaEntryDNParameter.getName());
1339    if (replicaEntryDNParameter != null)
1340    {
1341      replicaEntryDN = replicaEntryDNParameter.getStringValue();
1342    }
1343
1344
1345    // Get the delay between latency checks.
1346
latencyDelay = 0;
1347    replicaDelayParameter =
1348         parameters.getIntegerParameter(replicaDelayParameter.getName());
1349    if (replicaDelayParameter != null)
1350    {
1351      latencyDelay = replicaDelayParameter.getIntValue();
1352    }
1353
1354
1355    // Get the DN to use to bind to the directory server.
1356
bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1357    if (bindDNParameter == null)
1358    {
1359      bindDN = "";
1360    }
1361    else
1362    {
1363      bindDN = bindDNParameter.getStringValue();
1364    }
1365
1366    // Get the password to use to bind to the directory server.
1367
bindPWParameter =
1368         parameters.getPasswordParameter(bindPWParameter.getName());
1369    if (bindPWParameter == null)
1370    {
1371      bindPW = "";
1372    }
1373    else
1374    {
1375      bindPW = bindPWParameter.getStringValue();
1376    }
1377
1378    // Get the search base
1379
searchBaseParameter =
1380         parameters.getStringParameter(searchBaseParameter.getName());
1381    if (searchBaseParameter != null)
1382    {
1383      searchBase = searchBaseParameter.getStringValue();
1384    }
1385
1386
1387    // Get the data from the login ID file.
1388
useDataFile = false;
1389    loginDataFileParameter =
1390         parameters.getFileURLParameter(loginDataFileParameter.getName());
1391    if ((loginDataFileParameter != null) && (loginDataFileParameter.hasValue()))
1392    {
1393      String JavaDoc[] fileLines;
1394      try
1395      {
1396        fileLines = loginDataFileParameter.getNonBlankFileLines();
1397      }
1398      catch (Exception JavaDoc e)
1399      {
1400        throw new UnableToRunException("Unable to retrieve the login data " +
1401                                       "from the file: " + e, e);
1402      }
1403
1404      // Break the login data up into ID and passwords
1405
ArrayList loginIDList = new ArrayList(fileLines.length);
1406      ArrayList passwordList = new ArrayList(fileLines.length);
1407      for (int i=0; i < fileLines.length; i++)
1408      {
1409        try
1410        {
1411          StringTokenizer tokenizer = new StringTokenizer(fileLines[i], "\t");
1412          String JavaDoc loginID = tokenizer.nextToken();
1413          String JavaDoc password = tokenizer.nextToken();
1414          loginIDList.add(loginID);
1415          passwordList.add(password);
1416        } catch (Exception JavaDoc e) {}
1417      }
1418
1419      // Convert the lists into arrays and make sure that at least one login
1420
// ID/password has been provided.
1421
loginIDs = new String JavaDoc[loginIDList.size()];
1422      loginPasswords = new String JavaDoc[passwordList.size()];
1423      loginIDList.toArray(loginIDs);
1424      passwordList.toArray(loginPasswords);
1425      if (loginIDs.length == 0)
1426      {
1427        throw new UnableToRunException("No login IDs/passwords extracted from " +
1428                                       "the login data file.");
1429      }
1430
1431      useDataFile = true;
1432    }
1433    else
1434    {
1435      loginPasswordParameter =
1436           parameters.getPasswordParameter(loginPasswordParameter.getName());
1437      if ((loginPasswordParameter != null) &&
1438            (loginPasswordParameter.hasValue()))
1439      {
1440        loginPassword = loginPasswordParameter.getStringValue();
1441      }
1442
1443      loginIDValueParameter =
1444           parameters.getStringParameter(loginIDValueParameter.getName());
1445      useLoginIDRange = true;
1446      useSequential = false;
1447      String JavaDoc loginIDValue = loginIDValueParameter.getStringValue();
1448      try
1449      {
1450        int openPos = loginIDValue.indexOf('[');
1451        int closePos = loginIDValue.indexOf(']', openPos);
1452        loginIDInitial = loginIDValue.substring(0, openPos);
1453        loginIDFinal = loginIDValue.substring(closePos+1);
1454
1455        int dashPos = loginIDValue.indexOf('-', openPos);
1456        if (dashPos < 0)
1457        {
1458          dashPos = loginIDValue.indexOf(':', openPos);
1459          useSequential = true;
1460        }
1461
1462        loginIDMin = Integer.parseInt(loginIDValue.substring(openPos+1,
1463                                                              dashPos));
1464        loginIDMax = Integer.parseInt(loginIDValue.substring(dashPos+1,
1465                                                              closePos));
1466        loginIDSpan = loginIDMax - loginIDMin + 1;
1467        sequentialCounter = loginIDMin;
1468      }
1469      catch (Exception JavaDoc e)
1470      {
1471        useLoginIDRange = false;
1472        loginIDInitial = loginIDValue;
1473      }
1474    }
1475
1476
1477    // Get the login ID attribute.
1478
loginIDParameter =
1479         parameters.getStringParameter(loginIDParameter.getName());
1480    if (loginIDParameter != null)
1481    {
1482      loginIDAttr = loginIDParameter.getStringValue();
1483    }
1484
1485
1486    // Get the attributes to retrieve.
1487
attr1Parameter = parameters.getStringParameter(attr1Parameter.getName());
1488    if (attr1Parameter != null)
1489    {
1490      searchAttr1 = attr1Parameter.getStringValue();
1491      filter1 = "(" + searchAttr1 + "=*)";
1492      returnAttrs1 = new String JavaDoc[] { searchAttr1 };
1493    }
1494
1495    attr2Parameter = parameters.getStringParameter(attr2Parameter.getName());
1496    if (attr2Parameter != null)
1497    {
1498      searchAttr2 = attr2Parameter.getStringValue();
1499      filter2 = "(" + searchAttr2 + "=*)";
1500      returnAttrs2 = new String JavaDoc[] { searchAttr2 };
1501    }
1502
1503    attr3Parameter = parameters.getStringParameter(attr3Parameter.getName());
1504    if (attr3Parameter != null)
1505    {
1506      searchAttr3 = attr3Parameter.getStringValue();
1507      filter3 = "(" + searchAttr3 + "=*)";
1508      returnAttrs3 = new String JavaDoc[] { searchAttr3 };
1509    }
1510
1511    returnAttrsOC = new String JavaDoc[] { "objectClass" };
1512
1513
1514    // Get the attributes to modify.
1515
modAttrs = null;
1516    modAttrsParameter =
1517         parameters.getMultiLineTextParameter(modAttrsParameter.getName());
1518    if ((modAttrsParameter != null) && (modAttrsParameter.hasValue()))
1519    {
1520      modAttrs = modAttrsParameter.getNonBlankLines();
1521    }
1522
1523    // Determine whether to skip the bind attempt.
1524
skipBind = false;
1525    skipBindParameter =
1526         parameters.getBooleanParameter(skipBindParameter.getName());
1527    if (skipBindParameter != null)
1528    {
1529      skipBind = skipBindParameter.getBooleanValue();
1530    }
1531
1532    // Get the warm up time.
1533
warmUpTime = 0;
1534    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1535    if (warmUpParameter != null)
1536    {
1537      warmUpTime = warmUpParameter.getIntValue();
1538    }
1539
1540    // Get the cool down time.
1541
coolDownTime = 0;
1542    coolDownParameter =
1543         parameters.getIntegerParameter(coolDownParameter.getName());
1544    if (coolDownParameter != null)
1545    {
1546      coolDownTime = coolDownParameter.getIntValue();
1547    }
1548
1549    // Get the max operation time limit.
1550
timeLimitParameter =
1551         parameters.getIntegerParameter(timeLimitParameter.getName());
1552    if (timeLimitParameter != null)
1553    {
1554      timeLimit = timeLimitParameter.getIntValue();
1555    }
1556
1557    // Get the delay between authentication attempts.
1558
delay = 0;
1559    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1560    if (delayParameter != null)
1561    {
1562      delay = delayParameter.getIntValue();
1563    }
1564
1565
1566    // Get the indicator that specifies whether to ignore invalid credentials
1567
// errors.
1568
ignoreInvCredParameter =
1569         parameters.getBooleanParameter(ignoreInvCredParameter.getName());
1570    if (ignoreInvCredParameter != null)
1571    {
1572      ignoreInvalidCredentials = ignoreInvCredParameter.getBooleanValue();
1573    }
1574
1575    // Get the indicator that specifies whether to use shared connections.
1576
shareConnsParameter =
1577         parameters.getBooleanParameter(shareConnsParameter.getName());
1578    if (shareConnsParameter != null)
1579    {
1580      useSharedConnections = shareConnsParameter.getBooleanValue();
1581    }
1582
1583
1584    // If we are to use shared connections, then establish them now.
1585
if (useSharedConnections)
1586    {
1587      sharedAuthConnection = new LDAPConnection();
1588      sharedBindConnection = new LDAPConnection();
1589
1590      try
1591      {
1592        sharedAuthConnection.connect(3, masterHost, masterPort, bindDN,
1593                                     bindPW);
1594        sharedBindConnection.connect(3, masterHost, masterPort, "", "");
1595      }
1596      catch (Exception JavaDoc e)
1597      {
1598        throw new UnableToRunException("Could not establish shared " +
1599                                       "connections to the directory: " + e,
1600                                       e);
1601      }
1602    }
1603
1604
1605    // Seed the parent random number generator.
1606
parentRandom = new Random();
1607  }
1608
1609
1610
1611  /**
1612   * Initializes this job class with the information that it will use when
1613   * actually running the job. This will also initialize the stat trackers used
1614   * by the job.
1615   *
1616   * @param clientID The thread ID for this thread.
1617   * @param threadID The thread ID for this thread.
1618   * @param collectionInterval The collection interval to use for gathering
1619   * statistics while processing the job.
1620   * @param parameters The st of parameters that contain the
1621   * information used to customize the way this job
1622   * is processed.
1623   *
1624   * @throws UnableToRunException If a problem occurs that prevents the thread
1625   * from being able to run properly.
1626   */

1627  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1628                               int collectionInterval, ParameterList parameters)
1629         throws UnableToRunException
1630  {
1631    // Seed the random number generator for this thread.
1632
random = new Random(parentRandom.nextLong());
1633
1634    // If we are not going to use shared connections, then create the
1635
// connections for use by this thread. Otherwise, just grab the shared
1636
// connections.
1637
if (useSharedConnections)
1638    {
1639      authConnection = sharedAuthConnection;
1640      bindConnection = sharedBindConnection;
1641    }
1642    else
1643    {
1644      authConnection = new LDAPConnection();
1645      bindConnection = new LDAPConnection();
1646
1647      try
1648      {
1649        authConnection.connect(3, masterHost, masterPort, bindDN, bindPW);
1650        bindConnection.connect(3, masterHost, masterPort, "", "");
1651      }
1652      catch (Exception JavaDoc e)
1653      {
1654        throw new UnableToRunException("Unable to establish the connections " +
1655                                       "to the directory server: " + e, e);
1656      }
1657    }
1658
1659    // Initialize the constraints.
1660
authConstraints = authConnection.getConstraints();
1661    bindConstraints = bindConnection.getConstraints();
1662    authSearchConstraints = authConnection.getSearchConstraints();
1663    authConstraints.setTimeLimit(1000*timeLimit);
1664    bindConstraints.setTimeLimit(1000*timeLimit);
1665    authSearchConstraints.setTimeLimit(1000*timeLimit);
1666    authSearchConstraints.setServerTimeLimit(timeLimit);
1667
1668
1669    // Create the stat trackers.
1670
attemptCounter =
1671         new IncrementalTracker(clientID, threadID,
1672                                STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
1673                                collectionInterval);
1674    successCounter =
1675         new IncrementalTracker(clientID, threadID,
1676                                STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
1677                                collectionInterval);
1678    failureCounter =
1679         new IncrementalTracker(clientID, threadID,
1680                                STAT_TRACKER_FAILED_AUTHENTICATIONS,
1681                                collectionInterval);
1682    bindCounter = new IncrementalTracker(clientID, threadID,
1683                                         STAT_TRACKER_NUM_BINDS,
1684                                         collectionInterval);
1685    modCounter = new IncrementalTracker(clientID, threadID,
1686                                        STAT_TRACKER_NUM_MODS,
1687                                        collectionInterval);
1688    searchCounter = new IncrementalTracker(clientID, threadID,
1689                                           STAT_TRACKER_NUM_SEARCH,
1690                                           collectionInterval);
1691    authTimer = new TimeTracker(clientID, threadID,
1692                                STAT_TRACKER_AUTHENTICATION_TIME,
1693                                collectionInterval);
1694    bindTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_BIND_TIME,
1695                                collectionInterval);
1696    modTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_TIME,
1697                               collectionInterval);
1698    initialSearchTimer = new TimeTracker(clientID, threadID,
1699                                         STAT_TRACKER_INITIAL_SEARCH_TIME,
1700                                         collectionInterval);
1701    subsequentSearchTimer = new TimeTracker(clientID, threadID,
1702                                            STAT_TRACKER_SUBSEQUENT_SEARCH_TIME,
1703                                            collectionInterval);
1704    failureReasonTracker = new CategoricalTracker(clientID, threadID,
1705                                                  STAT_TRACKER_FAIL_REASON,
1706                                                  collectionInterval);
1707
1708
1709    // Enable real-time reporting of the data for these stat trackers.
1710
RealTimeStatReporter statReporter = getStatReporter();
1711    if (statReporter != null)
1712    {
1713      String JavaDoc jobID = getJobID();
1714      attemptCounter.enableRealTimeStats(statReporter, jobID);
1715      successCounter.enableRealTimeStats(statReporter, jobID);
1716      failureCounter.enableRealTimeStats(statReporter, jobID);
1717      bindCounter.enableRealTimeStats(statReporter, jobID);
1718      modCounter.enableRealTimeStats(statReporter, jobID);
1719      searchCounter.enableRealTimeStats(statReporter, jobID);
1720      authTimer.enableRealTimeStats(statReporter, jobID);
1721      bindTimer.enableRealTimeStats(statReporter, jobID);
1722      modTimer.enableRealTimeStats(statReporter, jobID);
1723      initialSearchTimer.enableRealTimeStats(statReporter, jobID);
1724      subsequentSearchTimer.enableRealTimeStats(statReporter, jobID);
1725    }
1726
1727
1728    // See if this thread should be used to report the replica latency
1729
// information. If so, then start the latency check threads.
1730
if ((! latencyTrackerChosen) && (getClientNumber() == 0))
1731    {
1732      latencyCheckMutex = new Object JavaDoc();
1733      latencyTrackerChosen = true;
1734      reportLatencyTracker = true;
1735
1736      // Create the latency timer stat tracker.
1737
latencyTime = new TimeTracker(clientID, threadID,
1738                                    STAT_TRACKER_REPLICATION_LATENCY,
1739                                    collectionInterval);
1740      if (statReporter != null)
1741      {
1742        latencyTime.enableRealTimeStats(statReporter, getJobID());
1743      }
1744
1745      // Create the latency categories stat tracker.
1746
latencyCategories =
1747           new CategoricalTracker(clientID, threadID,
1748                                  STAT_TRACKER_CATEGORIZED_LATENCY,
1749                                  collectionInterval);
1750
1751      // Create the latency thread that will make changes to the master server.
1752
try
1753      {
1754        masterThread =
1755             new LatencyCheckMasterThread(this, masterHost, masterPort, bindDN,
1756                                          bindPW, replicaEntryDN,
1757                                          modAttrs[0], latencyDelay);
1758      }
1759      catch (LDAPException le)
1760      {
1761        throw new UnableToRunException("Could not create the master latency " +
1762                                       "thread: " + le, le);
1763      }
1764
1765      // Create the latency thread that will read changes from the replica.
1766
try
1767      {
1768        replicaThread =
1769             new LatencyCheckReplicaThread(this, replicaHost, replicaPort,
1770                                           bindDN, bindPW,
1771                                           replicaEntryDN);
1772      }
1773      catch (LDAPException le)
1774      {
1775        throw new UnableToRunException("Could not create the replica latency " +
1776                                       "thread: " + le, le);
1777      }
1778
1779      // Start the latency check threads.
1780
masterThread.start();
1781      replicaThread.start();
1782    }
1783    else
1784    {
1785      reportLatencyTracker = false;
1786    }
1787  }
1788
1789
1790
1791  /**
1792   * Performs the work of actually running the job. When this method completes,
1793   * the job will be done.
1794   */

1795  public void runJob()
1796  {
1797    // Determine the range of time for which we should collect statistics.
1798
long currentTime = System.currentTimeMillis();
1799    boolean collectingStats = false;
1800    long startCollectingTime = currentTime + (1000 * warmUpTime);
1801    long stopCollectingTime = Long.MAX_VALUE;
1802    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1803    {
1804      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1805    }
1806
1807    // Define a variable that will be used to determine how long to sleep
1808
// between attempts.
1809
long authStartTime = 0;
1810
1811
1812    // Loop until it is time to stop.
1813
while (! shouldStop())
1814    {
1815      currentTime = System.currentTimeMillis();
1816      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1817          (currentTime < stopCollectingTime))
1818      {
1819        // Start all the stat trackers.
1820
attemptCounter.startTracker();
1821        successCounter.startTracker();
1822        failureCounter.startTracker();
1823        authTimer.startTracker();
1824        bindCounter.startTracker();
1825        modCounter.startTracker();
1826        searchCounter.startTracker();
1827        bindTimer.startTracker();
1828        modTimer.startTracker();
1829        initialSearchTimer.startTracker();
1830        subsequentSearchTimer.startTracker();
1831        failureReasonTracker.startTracker();
1832
1833        if (reportLatencyTracker)
1834        {
1835          latencyTime.startTracker();
1836          latencyCategories.startTracker();
1837          replicaThread.startChecking();
1838          masterThread.startChecking();
1839        }
1840
1841        collectingStats = true;
1842      }
1843      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1844      {
1845        attemptCounter.stopTracker();
1846        successCounter.stopTracker();
1847        failureCounter.stopTracker();
1848        authTimer.stopTracker();
1849        bindCounter.stopTracker();
1850        modCounter.stopTracker();
1851        searchCounter.stopTracker();
1852        bindTimer.stopTracker();
1853        modTimer.stopTracker();
1854        initialSearchTimer.stopTracker();
1855        subsequentSearchTimer.stopTracker();
1856        failureReasonTracker.stopTracker();
1857
1858        if (reportLatencyTracker)
1859        {
1860          latencyTime.stopTracker();
1861          latencyCategories.stopTracker();
1862          replicaThread.stopAndWait();
1863          masterThread.stopAndWait();
1864        }
1865
1866        collectingStats = false;
1867      }
1868
1869      // See if we need to sleep before the next attempt
1870
if ((delay > 0) && (authStartTime > 0))
1871      {
1872        long now = System.currentTimeMillis();
1873        long sleepTime = delay - (now - authStartTime);
1874        if (sleepTime > 0)
1875        {
1876          try
1877          {
1878            Thread.sleep(sleepTime);
1879          } catch (InterruptedException JavaDoc ie) {}
1880
1881          if (shouldStop())
1882          {
1883            break;
1884          }
1885        }
1886      }
1887
1888      // Get a random user number and translate that to a login ID and password.
1889
String JavaDoc[] loginInfo = getLoginInfo();
1890      String JavaDoc loginID = loginInfo[0];
1891      String JavaDoc password = loginInfo[1];
1892
1893
1894      // Start the auth attempt timer now.
1895
if (delay > 0)
1896      {
1897        authStartTime = System.currentTimeMillis();
1898      }
1899
1900
1901      // Increment the number of authentication attempts and start the timer
1902
if (collectingStats)
1903      {
1904        attemptCounter.increment();
1905        authTimer.startTimer();
1906      }
1907
1908      String JavaDoc failureReason = "Search 1";
1909
1910      try
1911      {
1912        // First, issue a search to try to find the user's entry.
1913
String JavaDoc userDN = null;
1914        String JavaDoc filter = "(" + loginIDAttr + "=" + loginID + ")";
1915        LDAPSearchResults results;
1916        if (collectingStats)
1917        {
1918          searchCounter.increment();
1919          initialSearchTimer.startTimer();
1920        }
1921        results = authConnection.search(searchBase, LDAPConnection.SCOPE_SUB,
1922                                        filter, returnAttrsOC, false,
1923                                        authSearchConstraints);
1924        while (results.hasMoreElements())
1925        {
1926          Object JavaDoc element = results.nextElement();
1927          if (element instanceof LDAPEntry)
1928          {
1929            userDN = ((LDAPEntry) element).getDN();
1930          }
1931        }
1932        if (collectingStats)
1933        {
1934          initialSearchTimer.stopTimer();
1935        }
1936
1937        // Make sure that we got a user DN. If not, then it's a failed attempt.
1938
if (userDN == null)
1939        {
1940          if (collectingStats)
1941          {
1942            failureCounter.increment();
1943            authTimer.stopTimer();
1944            failureReasonTracker.increment(failureReason);
1945          }
1946          continue;
1947        }
1948
1949        // Now do a base-level search on the user's entry to retrieve the
1950
// objectClass attribute.
1951
failureReason = "Search 2";
1952        filter = "(objectClass=*)";
1953        if (collectingStats)
1954        {
1955          searchCounter.increment();
1956          subsequentSearchTimer.startTimer();
1957        }
1958        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1959                                        filter, returnAttrsOC, false,
1960                                        authSearchConstraints);
1961        while (results.hasMoreElements())
1962        {
1963          results.nextElement();
1964        }
1965        if (collectingStats)
1966        {
1967          subsequentSearchTimer.stopTimer();
1968        }
1969
1970        // Now bind as the user.
1971
if (! skipBind)
1972        {
1973          failureReason = "Bind";
1974
1975          try
1976          {
1977            if (collectingStats)
1978            {
1979              bindCounter.increment();
1980              bindTimer.startTimer();
1981            }
1982            bindConnection.authenticate(3, userDN, password, bindConstraints);
1983            if (collectingStats)
1984            {
1985              bindTimer.stopTimer();
1986            }
1987          }
1988          catch (LDAPException le)
1989          {
1990            if (collectingStats)
1991            {
1992              bindTimer.stopTimer();
1993            }
1994
1995            if (le.getLDAPResultCode() == LDAPException.INVALID_CREDENTIALS)
1996            {
1997              if (! ignoreInvalidCredentials)
1998              {
1999                if (collectingStats)
2000                {
2001                  failureCounter.increment();
2002                  authTimer.stopTimer();
2003                  failureReasonTracker.increment(failureReason);
2004                }
2005                continue;
2006              }
2007            }
2008            else
2009            {
2010              if (collectingStats)
2011              {
2012                failureCounter.increment();
2013                authTimer.stopTimer();
2014                failureReasonTracker.increment(failureReason);
2015              }
2016              continue;
2017            }
2018          }
2019        }
2020
2021        // Now retrieve the "attr1" attribute from the user's entry.
2022
failureReason = "Search 3";
2023        if (collectingStats)
2024        {
2025          searchCounter.increment();
2026          subsequentSearchTimer.startTimer();
2027        }
2028        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2029                                        filter1, returnAttrs1, false,
2030                                        authSearchConstraints);
2031        while (results.hasMoreElements())
2032        {
2033          results.nextElement();
2034        }
2035        if (collectingStats)
2036        {
2037          subsequentSearchTimer.stopTimer();
2038        }
2039
2040        // Retrieve the "attr2" attribute from the user's entry.
2041
failureReason = "Search 4";
2042        if (collectingStats)
2043        {
2044          searchCounter.increment();
2045          subsequentSearchTimer.startTimer();
2046        }
2047        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2048                                        filter2, returnAttrs2, false,
2049                                        authSearchConstraints);
2050        while (results.hasMoreElements())
2051        {
2052          results.nextElement();
2053        }
2054        if (collectingStats)
2055        {
2056          subsequentSearchTimer.stopTimer();
2057        }
2058
2059        // Retrieve the first attribute again.
2060
failureReason = "Search 5";
2061        if (collectingStats)
2062        {
2063          searchCounter.increment();
2064          subsequentSearchTimer.startTimer();
2065        }
2066        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2067                                        filter1, returnAttrs1, false,
2068                                        authSearchConstraints);
2069        while (results.hasMoreElements())
2070        {
2071          results.nextElement();
2072        }
2073        if (collectingStats)
2074        {
2075          subsequentSearchTimer.stopTimer();
2076        }
2077
2078        // Perform a modification on the entry
2079
if ((modAttrs != null) && (modAttrs.length > 0))
2080        {
2081          failureReason = "Modify";
2082          LDAPModificationSet modSet = new LDAPModificationSet();
2083          for (int i=0; i < modAttrs.length; i++)
2084          {
2085            LDAPAttribute attr = new LDAPAttribute(modAttrs[i],
2086                                                   getRandomString(80));
2087            modSet.add(LDAPModification.REPLACE, attr);
2088          }
2089          if (collectingStats)
2090          {
2091            modCounter.increment();
2092            modTimer.startTimer();
2093          }
2094          authConnection.modify(userDN, modSet, authConstraints);
2095          if (collectingStats)
2096          {
2097            modTimer.stopTimer();
2098          }
2099        }
2100
2101        // Retrieve the first attribute again.
2102
failureReason = "Search 6";
2103        if (collectingStats)
2104        {
2105          searchCounter.increment();
2106          subsequentSearchTimer.startTimer();
2107        }
2108        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2109                                        filter1, returnAttrs1, false,
2110                                        authSearchConstraints);
2111        while (results.hasMoreElements())
2112        {
2113          results.nextElement();
2114        }
2115        if (collectingStats)
2116        {
2117          subsequentSearchTimer.stopTimer();
2118        }
2119
2120        // Retrieve the first attribute again.
2121
failureReason = "Search 7";
2122        if (collectingStats)
2123        {
2124          searchCounter.increment();
2125          subsequentSearchTimer.startTimer();
2126        }
2127        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2128                                        filter1, returnAttrs1, false,
2129                                        authSearchConstraints);
2130        while (results.hasMoreElements())
2131        {
2132          results.nextElement();
2133        }
2134        if (collectingStats)
2135        {
2136          subsequentSearchTimer.stopTimer();
2137        }
2138
2139        // Retrieve the third attribute.
2140
failureReason = "Search 8";
2141        if (collectingStats)
2142        {
2143          searchCounter.increment();
2144          subsequentSearchTimer.startTimer();
2145        }
2146        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2147                                        filter3, returnAttrs3, false,
2148                                        authSearchConstraints);
2149        while (results.hasMoreElements())
2150        {
2151          results.nextElement();
2152        }
2153        if (collectingStats)
2154        {
2155          subsequentSearchTimer.stopTimer();
2156        }
2157      }
2158      catch (Exception JavaDoc e)
2159      {
2160
2161        if (collectingStats)
2162        {
2163          failureCounter.increment();
2164          authTimer.stopTimer();
2165          failureReasonTracker.increment(failureReason);
2166        }
2167        continue;
2168      }
2169
2170
2171      // If we have gotten here, then everything is done and we can consider the
2172
// authentication successful.
2173
if (collectingStats)
2174      {
2175        successCounter.increment();
2176        authTimer.stopTimer();
2177      }
2178    }
2179
2180
2181    // Stop all the stat trackers.
2182
if (collectingStats)
2183    {
2184      attemptCounter.stopTracker();
2185      successCounter.stopTracker();
2186      failureCounter.stopTracker();
2187      authTimer.stopTracker();
2188      bindCounter.stopTracker();
2189      modCounter.stopTracker();
2190      searchCounter.stopTracker();
2191      bindTimer.stopTracker();
2192      modTimer.stopTracker();
2193      initialSearchTimer.stopTracker();
2194      subsequentSearchTimer.stopTracker();
2195      failureReasonTracker.stopTracker();
2196
2197      if (reportLatencyTracker)
2198      {
2199        latencyTime.stopTracker();
2200        latencyCategories.stopTracker();
2201        replicaThread.stopAndWait();
2202        masterThread.stopAndWait();
2203      }
2204    }
2205
2206
2207    // Close the connections to the directory server if appropriate.
2208
if (! useSharedConnections)
2209    {
2210      try
2211      {
2212        authConnection.disconnect();
2213      } catch (Exception JavaDoc e) {}
2214
2215      try
2216      {
2217        bindConnection.disconnect();
2218      } catch (Exception JavaDoc e) {}
2219    }
2220  }
2221
2222
2223
2224  /**
2225   * Attempts to force this thread to exit by closing the connection to the
2226   * directory server and setting it to <CODE>null</CODE>.
2227   */

2228  public void destroy()
2229  {
2230    if (authConnection != null)
2231    {
2232      try
2233      {
2234        authConnection.disconnect();
2235      } catch (Exception JavaDoc e) {}
2236
2237      authConnection = null;
2238    }
2239
2240    if (bindConnection != null)
2241    {
2242      try
2243      {
2244        bindConnection.disconnect();
2245      } catch (Exception JavaDoc e) {}
2246
2247      bindConnection = null;
2248    }
2249
2250    if (masterThread != null)
2251    {
2252      masterThread.masterThread.interrupt();
2253
2254      try
2255      {
2256        masterThread.connection.disconnect();
2257      } catch (Exception JavaDoc e) {}
2258
2259      masterThread.connection = null;
2260      masterThread = null;
2261    }
2262
2263    if (replicaThread != null)
2264    {
2265      replicaThread.replicaThread.interrupt();
2266
2267      try
2268      {
2269        replicaThread.connection.disconnect();
2270      } catch (Exception JavaDoc e) {}
2271
2272      replicaThread.connection = null;
2273      replicaThread = null;
2274    }
2275  }
2276
2277
2278
2279  /**
2280   * Performs any per-client finalization that should be done for this job. In
2281   * this case, if the job was using shared connections then those connections
2282   * will be closed.
2283   */

2284  public void finalizeClient()
2285  {
2286    // Make sure that the shared connections get closed properly.
2287
if (useSharedConnections)
2288    {
2289      try
2290      {
2291        sharedAuthConnection.disconnect();
2292      } catch (Exception JavaDoc e) {}
2293
2294      try
2295      {
2296        sharedBindConnection.disconnect();
2297      } catch (Exception JavaDoc e) {}
2298    }
2299  }
2300
2301
2302
2303  /**
2304   * Retrieves an array containing the login ID and password that should be
2305   * used to authenticate to the directory.
2306   *
2307   * @return An array containing the login ID and password.
2308   */

2309  public String JavaDoc[] getLoginInfo()
2310  {
2311    String JavaDoc[] loginInfo = new String JavaDoc[2];
2312
2313    if (useDataFile)
2314    {
2315      int slot = (random.nextInt() & 0x7FFFFFFF) % loginIDs.length;
2316      loginInfo[0] = loginIDs[slot];
2317      loginInfo[1] = loginPasswords[slot];
2318    }
2319    else
2320    {
2321      if (useLoginIDRange)
2322      {
2323        int value;
2324        if (useSequential)
2325        {
2326          value = sequentialCounter++;
2327          if (sequentialCounter > loginIDMax)
2328          {
2329            sequentialCounter = loginIDMax;
2330          }
2331        }
2332        else
2333        {
2334          value = ((random.nextInt() & 0x7FFFFFFF) % loginIDSpan) + loginIDMin;
2335        }
2336
2337        loginInfo[0] = loginIDInitial + value + loginIDFinal;
2338        loginInfo[1] = loginPassword;
2339      }
2340      else
2341      {
2342        loginInfo[0] = loginIDInitial;
2343        loginInfo[1] = loginPassword;
2344      }
2345    }
2346
2347    return loginInfo;
2348  }
2349
2350
2351
2352  /**
2353   * Retrieves a string of random characters of the specified length.
2354   *
2355   * @param length The number of characters to include in the string.
2356   *
2357   * @return The generated string of random characters.
2358   */

2359  public String JavaDoc getRandomString(int length)
2360  {
2361    char[] returnArray = new char[length];
2362
2363    for (int i=0; i < returnArray.length; i++)
2364    {
2365      returnArray[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
2366                                ALPHABET.length];
2367    }
2368
2369    return new String JavaDoc(returnArray);
2370  }
2371}
2372
2373
Popular Tags