KickJava   Java API By Example, From Geeks To Geeks.

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


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

61 public class SiteMinderJobClass
62        extends JobClass
63 {
64   /**
65    * The set of characters that will be used to generate random values for the
66    * modifications.
67    */

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

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

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

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

100   public static final String JavaDoc DEFAULT_LOG_ID_ATTR = "uid";
101
102
103
104   /**
105    * The system property used to specify the location of the JSSE key store.
106    */

107   public static final String JavaDoc SSL_KEY_STORE_PROPERTY =
108        "javax.net.ssl.keyStore";
109
110
111
112   /**
113    * The system property used to specify the password for the JSSE key store.
114    */

115   public static final String JavaDoc SSL_KEY_PASSWORD_PROPERTY =
116        "javax.net.ssl.keyStorePassword";
117
118
119
120   /**
121    * The system property used to specify the location of the JSSE trust store.
122    */

123   public static final String JavaDoc SSL_TRUST_STORE_PROPERTY =
124        "javax.net.ssl.trustStore";
125
126
127
128   /**
129    * The system property used to specify the password for the JSSE trust store.
130    */

131   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
132        "javax.net.ssl.trustStorePassword";
133
134
135
136   /**
137    * The name of the stat tracker that will be used to count the number of
138    * authentication attempts.
139    */

140   public static final String JavaDoc STAT_TRACKER_AUTHENTICATION_ATTEMPTS =
141        "Authentication Attempts";
142
143
144
145
146   /**
147    * The name of the stat tracker that will be used to keep track of the time
148    * required to perform each authentication.
149    */

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

159   public static final String JavaDoc STAT_TRACKER_BIND_TIME = "Bind Time (ms)";
160
161
162
163
164   /**
165    * The name of the stat tracker that will be used to count the number of
166    * failed authentications.
167    */

168   public static final String JavaDoc STAT_TRACKER_FAILED_AUTHENTICATIONS =
169        "Failed Authentications";
170
171
172
173   /**
174    * The name of the stat tracker that will be used to categorize the reasons
175    * for the failed auths.
176    */

177   public static final String JavaDoc STAT_TRACKER_FAIL_REASON = "Failure Reason";
178
179
180
181   /**
182    * The name of the stat tracker that will be used to keep track of the time
183    * required to perform the initial search (to find the user's entry).
184    */

185   public static final String JavaDoc STAT_TRACKER_INITIAL_SEARCH_TIME =
186        "Initial Search Time (ms)";
187
188
189
190   /**
191    * The name of the stat tracker that will be used to keep track of the time
192    * required to perform each modification.
193    */

194   public static final String JavaDoc STAT_TRACKER_MOD_TIME = "Modify Time (ms)";
195
196
197
198   /**
199    * The name of the stat tracker that will be used to keep track of the number
200    * of bind operations performed.
201    */

202   public static final String JavaDoc STAT_TRACKER_NUM_BINDS =
203        "Bind Operations Performed";
204
205
206
207   /**
208    * The name of the stat tracker that will be used to keep track of the number
209    * of modify operations performed.
210    */

211   public static final String JavaDoc STAT_TRACKER_NUM_MODS =
212        "Modify Operations Performed";
213
214
215
216   /**
217    * The name of the stat tracker that will be used to keep track of the number
218    * of search operations performed.
219    */

220   public static final String JavaDoc STAT_TRACKER_NUM_SEARCH =
221        "Search Operations Performed";
222
223
224
225   /**
226    * The name of the stat tracker that will be used to keep track of the time
227    * required to perform subsequent searches (to retrieve specific attributes
228    * from the user's entry).
229    */

230   public static final String JavaDoc STAT_TRACKER_SUBSEQUENT_SEARCH_TIME =
231        "Subsequent Search Time (ms)";
232
233
234
235   /**
236    * The name of the stat tracker that will be used to count the number of
237    * successful authentications.
238    */

239   public static final String JavaDoc STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS =
240        "Successful Authentications";
241
242
243
244   /**
245    * The default set of attributes to include in the modification.
246    */

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

648   public SiteMinderJobClass()
649   {
650     super();
651   }
652
653
654
655   /**
656    * Returns the user-friendly name that is to be used for this job class in the
657    * administrative interface.
658    *
659    * @return The user-friendly name for this job class.
660    */

661   public String JavaDoc getJobName()
662   {
663     return "LDAP SiteMinder Load Simulator";
664   }
665
666
667
668   /**
669    * Returns a description of this job that can be seen in the administrative
670    * interface.
671    *
672    * @return A description of this job class.
673    */

674   public String JavaDoc getJobDescription()
675   {
676     return "This job simulates the load that SiteMinder can place on the " +
677            "directory server when it is performing authentications.";
678   }
679
680
681
682   /**
683    * Retrieves the name of the category in which this job class exists. This is
684    * used to help arrange the job classes in the administrative interface.
685    *
686    * @return The name of the category in which this job class exists.
687    */

688   public String JavaDoc getJobCategoryName()
689   {
690     return "LDAP";
691   }
692
693
694
695   /**
696    * Returns the set of parameters whose value may be specified by the end user.
697    *
698    * @return The set of configurable parameters for this job class.
699    */

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

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

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

850   public void validateJobInfo(int numClients, int threadsPerClient,
851                               int threadStartupDelay, Date startTime,
852                               Date stopTime, int duration,
853                               int collectionInterval, ParameterList parameters)
854          throws InvalidValueException
855   {
856     FileURLParameter loginDataURLParameter =
857          parameters.getFileURLParameter(loginDataFileParameter.getName());
858     if ((loginDataURLParameter == null) ||
859         (! loginDataURLParameter.hasValue()))
860     {
861       StringParameter loginValueParameter =
862            parameters.getStringParameter(loginIDValueParameter.getName());
863       PasswordParameter loginPWParameter =
864            parameters.getPasswordParameter(loginPasswordParameter.getName());
865
866       if ((loginValueParameter == null) ||
867           (! loginValueParameter.hasValue()) ||
868           (loginPWParameter == null) ||
869           (! loginPWParameter.hasValue()))
870       {
871         throw new InvalidValueException("You must specify either a login " +
872                                         "data file URL or a login ID value " +
873                                         "and password");
874       }
875     }
876   }
877
878
879
880   /**
881    * Indicates whether this job class implements logic that makes it possible to
882    * test the validity of job parameters before scheduling the job for execution
883    * (e.g., to see if the server is reachable using the information provided).
884    *
885    * @return <CODE>true</CODE> if this job provides a means of testing the job
886    * parameters, or <CODE>false</CODE> if not.
887    */

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

922   public boolean testJobParameters(ParameterList parameters,
923                                    ArrayList outputMessages)
924   {
925     // Get all the parameters that we might need to perform the test.
926
StringParameter hostParam =
927          parameters.getStringParameter(hostParameter.getName());
928     if ((hostParam == null) || (! hostParam.hasValue()))
929     {
930       outputMessages.add("ERROR: No directory server address was provided.");
931       return false;
932     }
933     String JavaDoc host = hostParam.getStringValue();
934
935
936     IntegerParameter portParam =
937          parameters.getIntegerParameter(portParameter.getName());
938     if ((portParam == null) || (! hostParam.hasValue()))
939     {
940       outputMessages.add("ERROR: No directory server port was provided.");
941       return false;
942     }
943     int port = portParam.getIntValue();
944
945
946     boolean useSSL = false;
947     BooleanParameter useSSLParam =
948          parameters.getBooleanParameter(useSSLParameter.getName());
949     if (useSSLParam != null)
950     {
951       useSSL = useSSLParam.getBooleanValue();
952     }
953
954
955     boolean blindTrust = true;
956     BooleanParameter blindTrustParam =
957          parameters.getBooleanParameter(blindTrustParameter.getName());
958     if (blindTrustParam != null)
959     {
960       blindTrust = blindTrustParam.getBooleanValue();
961     }
962
963
964     String JavaDoc keyStore = null;
965     StringParameter keyStoreParam =
966          parameters.getStringParameter(keyStoreParameter.getName());
967     if ((keyStoreParam != null) && keyStoreParam.hasValue())
968     {
969       keyStore = keyStoreParam.getStringValue();
970       File keyStoreFile = new File(keyStore);
971       if (useSSL && (! blindTrust) && (! keyStoreFile.exists()))
972       {
973         outputMessages.add("WARNING: Key store file \"" + keyStore +
974                            "\" not found on SLAMD server system. This test " +
975                            "will blindly trust any SSL certificate " +
976                            "presented by the directory server.");
977         outputMessages.add("");
978         blindTrust = true;
979       }
980       else
981       {
982         System.setProperty(SSL_KEY_STORE_PROPERTY, keyStore);
983       }
984     }
985
986
987     String JavaDoc keyStorePassword = "";
988     StringParameter keyPassParam =
989          parameters.getStringParameter(keyPWParameter.getName());
990     if ((keyPassParam != null) && keyPassParam.hasValue())
991     {
992       keyStorePassword = keyPassParam.getStringValue();
993       System.setProperty(SSL_KEY_PASSWORD_PROPERTY, keyStorePassword);
994     }
995
996
997     String JavaDoc trustStore = null;
998     StringParameter trustStoreParam =
999          parameters.getStringParameter(trustStoreParameter.getName());
1000    if ((trustStoreParam != null) && trustStoreParam.hasValue())
1001    {
1002      trustStore = trustStoreParam.getStringValue();
1003      File trustStoreFile = new File(trustStore);
1004      if (useSSL && (! blindTrust) && (! trustStoreFile.exists()))
1005      {
1006        outputMessages.add("WARNING: trust store file \"" + trustStore +
1007                           "\" not found on SLAMD server system. This test " +
1008                           "will blindly trust any SSL certificate " +
1009                           "presented by the directory server.");
1010        outputMessages.add("");
1011        blindTrust = true;
1012      }
1013      else
1014      {
1015        System.setProperty(SSL_TRUST_STORE_PROPERTY, trustStore);
1016      }
1017    }
1018
1019
1020    String JavaDoc trustStorePassword = "";
1021    StringParameter trustPassParam =
1022         parameters.getStringParameter(trustPWParameter.getName());
1023    if ((trustPassParam != null) && trustPassParam.hasValue())
1024    {
1025      trustStorePassword = trustPassParam.getStringValue();
1026      System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, trustStorePassword);
1027    }
1028
1029
1030    String JavaDoc bindDN = "";
1031    StringParameter bindDNParam =
1032         parameters.getStringParameter(bindDNParameter.getName());
1033    if ((bindDNParam != null) && bindDNParam.hasValue())
1034    {
1035      bindDN = bindDNParam.getStringValue();
1036    }
1037
1038
1039    String JavaDoc bindPassword = "";
1040    PasswordParameter bindPWParam =
1041         parameters.getPasswordParameter(bindPWParameter.getName());
1042    if ((bindPWParam != null) && bindPWParam.hasValue())
1043    {
1044      bindPassword = bindPWParam.getStringValue();
1045    }
1046
1047
1048    StringParameter baseDNParam =
1049         parameters.getStringParameter(searchBaseParameter.getName());
1050    if ((baseDNParam == null) || (! baseDNParam.hasValue()))
1051    {
1052      outputMessages.add("ERROR: No base DN was provided.");
1053      return false;
1054    }
1055    String JavaDoc baseDN = baseDNParam.getStringValue();
1056
1057
1058    // Create the LDAPConnection object that we will use to communicate with the
1059
// directory server.
1060
LDAPConnection conn;
1061    if (useSSL)
1062    {
1063      if (blindTrust)
1064      {
1065        try
1066        {
1067          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1068        }
1069        catch (Exception JavaDoc e)
1070        {
1071          outputMessages.add("ERROR: Unable to instantiate the blind trust " +
1072                             "socket factory for use in creating the SSL " +
1073                             "connection: " + stackTraceToString(e));
1074          return false;
1075        }
1076      }
1077      else
1078      {
1079        conn = new LDAPConnection(new JSSESocketFactory(null));
1080      }
1081    }
1082    else
1083    {
1084      conn = new LDAPConnection();
1085    }
1086
1087
1088    // Attempt to establish a connection to the directory server.
1089
try
1090    {
1091      if (useSSL)
1092      {
1093        outputMessages.add("Attempting to establish an SSL-based connection " +
1094                           "to " + host + ":" + port + "....");
1095      }
1096      else
1097      {
1098        outputMessages.add("Attempting to establish a connection to " + host +
1099                           ":" + port + "....");
1100      }
1101      conn.connect(host, port);
1102      outputMessages.add("Connected successfully.");
1103      outputMessages.add("");
1104    }
1105    catch (Exception JavaDoc e)
1106    {
1107      outputMessages.add("ERROR: Unable to connect to the directory " +
1108                         "server: " + stackTraceToString(e));
1109      return false;
1110    }
1111
1112
1113    // Attempt to bind to the directory server using the bind DN and password.
1114
try
1115    {
1116      outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
1117                         "directory server with a DN of '" + bindDN + "'....");
1118      conn.bind(3, bindDN, bindPassword);
1119      outputMessages.add("Bound successfully.");
1120      outputMessages.add("");
1121    }
1122    catch (Exception JavaDoc e)
1123    {
1124      try
1125      {
1126        conn.disconnect();
1127      } catch (Exception JavaDoc e2) {}
1128
1129      outputMessages.add("ERROR: Unable to bind to the directory server: " +
1130                         stackTraceToString(e));
1131      return false;
1132    }
1133
1134
1135    // Make sure that the entry specified as the base DN exists.
1136
try
1137    {
1138      outputMessages.add("Checking to make sure that the base DN entry '" +
1139                         baseDN + "' exists in the directory....");
1140      LDAPEntry baseDNEntry = conn.read(baseDN, new String JavaDoc[] { "1.1" });
1141      if (baseDNEntry == null)
1142      {
1143        try
1144        {
1145          conn.disconnect();
1146        } catch (Exception JavaDoc e2) {}
1147
1148        outputMessages.add("ERROR: Unable to retrieve the base DN entry.");
1149        return false;
1150      }
1151      else
1152      {
1153        outputMessages.add("Successfully read the base DN entry.");
1154        outputMessages.add("");
1155      }
1156    }
1157    catch (Exception JavaDoc e)
1158    {
1159      try
1160      {
1161        conn.disconnect();
1162      } catch (Exception JavaDoc e2) {}
1163
1164      outputMessages.add("ERROR: Unable to retrieve the base DN entry: " +
1165                         stackTraceToString(e));
1166      return false;
1167    }
1168
1169
1170    // At this point, all tests have passed. Close the connection and return
1171
// true.
1172
try
1173    {
1174      conn.disconnect();
1175    } catch (Exception JavaDoc e) {}
1176
1177    outputMessages.add("All tests completed successfully.");
1178    return true;
1179  }
1180
1181
1182
1183  /**
1184   * Performs initialization for this job on each client immediately before each
1185   * thread is created to actually run the job.
1186   *
1187   * @param clientID The ID assigned to the client running this job.
1188   * @param parameters The set of parameters provided to this job that can be
1189   * used to customize its behavior.
1190   *
1191   * @throws UnableToRunException If the client initialization could not be
1192   * completed successfully and the job is unable
1193   * to run.
1194   */

1195  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1196         throws UnableToRunException
1197  {
1198    // Get the directory server address
1199
hostParameter = parameters.getStringParameter(hostParameter.getName());
1200    if (hostParameter == null)
1201    {
1202      throw new UnableToRunException("No directory server host provided.");
1203    }
1204    else
1205    {
1206      directoryHost = hostParameter.getStringValue();
1207    }
1208
1209
1210    // Get the directory server port
1211
portParameter = parameters.getIntegerParameter(portParameter.getName());
1212    if (portParameter != null)
1213    {
1214      directoryPort = portParameter.getIntValue();
1215    }
1216
1217    // Get the DN to use to bind to the directory server.
1218
bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1219    if (bindDNParameter == null)
1220    {
1221      bindDN = "";
1222    }
1223    else
1224    {
1225      bindDN = bindDNParameter.getStringValue();
1226    }
1227
1228    // Get the password to use to bind to the directory server.
1229
bindPWParameter =
1230         parameters.getPasswordParameter(bindPWParameter.getName());
1231    if (bindPWParameter == null)
1232    {
1233      bindPW = "";
1234    }
1235    else
1236    {
1237      bindPW = bindPWParameter.getStringValue();
1238    }
1239
1240    // Get the search base
1241
searchBaseParameter =
1242         parameters.getStringParameter(searchBaseParameter.getName());
1243    if (searchBaseParameter != null)
1244    {
1245      searchBase = searchBaseParameter.getStringValue();
1246    }
1247
1248
1249    // Get the data from the login ID file.
1250
useDataFile = false;
1251    loginDataFileParameter =
1252         parameters.getFileURLParameter(loginDataFileParameter.getName());
1253    if ((loginDataFileParameter != null) && (loginDataFileParameter.hasValue()))
1254    {
1255      String JavaDoc[] fileLines;
1256      try
1257      {
1258        fileLines = loginDataFileParameter.getNonBlankFileLines();
1259      }
1260      catch (Exception JavaDoc e)
1261      {
1262        throw new UnableToRunException("Unable to retrieve the login data " +
1263                                       "from the file: " + e, e);
1264      }
1265
1266      // Break the login data up into ID and passwords
1267
ArrayList loginIDList = new ArrayList(fileLines.length);
1268      ArrayList passwordList = new ArrayList(fileLines.length);
1269      for (int i=0; i < fileLines.length; i++)
1270      {
1271        try
1272        {
1273          StringTokenizer tokenizer = new StringTokenizer(fileLines[i], "\t");
1274          String JavaDoc loginID = tokenizer.nextToken();
1275          String JavaDoc password = tokenizer.nextToken();
1276          loginIDList.add(loginID);
1277          passwordList.add(password);
1278        } catch (Exception JavaDoc e) {}
1279      }
1280
1281      // Convert the lists into arrays and make sure that at least one login
1282
// ID/password has been provided.
1283
loginIDs = new String JavaDoc[loginIDList.size()];
1284      loginPasswords = new String JavaDoc[passwordList.size()];
1285      loginIDList.toArray(loginIDs);
1286      passwordList.toArray(loginPasswords);
1287      if (loginIDs.length == 0)
1288      {
1289        throw new UnableToRunException("No login IDs/passwords extracted from " +
1290                                       "the login data file.");
1291      }
1292
1293      useDataFile = true;
1294    }
1295    else
1296    {
1297      loginPasswordParameter =
1298           parameters.getPasswordParameter(loginPasswordParameter.getName());
1299      if ((loginPasswordParameter != null) &&
1300            (loginPasswordParameter.hasValue()))
1301      {
1302        loginPassword = loginPasswordParameter.getStringValue();
1303      }
1304
1305      loginIDValueParameter =
1306           parameters.getStringParameter(loginIDValueParameter.getName());
1307      useLoginIDRange = true;
1308      useSequential = false;
1309      String JavaDoc loginIDValue = loginIDValueParameter.getStringValue();
1310      try
1311      {
1312        int openPos = loginIDValue.indexOf('[');
1313        int closePos = loginIDValue.indexOf(']', openPos);
1314        loginIDInitial = loginIDValue.substring(0, openPos);
1315        loginIDFinal = loginIDValue.substring(closePos+1);
1316
1317        int dashPos = loginIDValue.indexOf('-', openPos);
1318        if (dashPos < 0)
1319        {
1320          dashPos = loginIDValue.indexOf(':', openPos);
1321          useSequential = true;
1322        }
1323
1324        loginIDMin = Integer.parseInt(loginIDValue.substring(openPos+1,
1325                                                              dashPos));
1326        loginIDMax = Integer.parseInt(loginIDValue.substring(dashPos+1,
1327                                                              closePos));
1328        loginIDSpan = loginIDMax - loginIDMin + 1;
1329        sequentialCounter = loginIDMin;
1330      }
1331      catch (Exception JavaDoc e)
1332      {
1333        useLoginIDRange = false;
1334        loginIDInitial = loginIDValue;
1335      }
1336    }
1337
1338
1339    // Get the login ID attribute.
1340
loginIDParameter =
1341         parameters.getStringParameter(loginIDParameter.getName());
1342    if (loginIDParameter != null)
1343    {
1344      loginIDAttr = loginIDParameter.getStringValue();
1345    }
1346
1347
1348    // Get the attributes to retrieve.
1349
attr1Parameter = parameters.getStringParameter(attr1Parameter.getName());
1350    if (attr1Parameter != null)
1351    {
1352      searchAttr1 = attr1Parameter.getStringValue();
1353      filter1 = "(" + searchAttr1 + "=*)";
1354      returnAttrs1 = new String JavaDoc[] { searchAttr1 };
1355    }
1356
1357    attr2Parameter = parameters.getStringParameter(attr2Parameter.getName());
1358    if (attr2Parameter != null)
1359    {
1360      searchAttr2 = attr2Parameter.getStringValue();
1361      filter2 = "(" + searchAttr2 + "=*)";
1362      returnAttrs2 = new String JavaDoc[] { searchAttr2 };
1363    }
1364
1365    attr3Parameter = parameters.getStringParameter(attr3Parameter.getName());
1366    if (attr3Parameter != null)
1367    {
1368      searchAttr3 = attr3Parameter.getStringValue();
1369      filter3 = "(" + searchAttr3 + "=*)";
1370      returnAttrs3 = new String JavaDoc[] { searchAttr3 };
1371    }
1372
1373    returnAttrsOC = new String JavaDoc[] { "objectClass" };
1374
1375
1376    // Get the attributes to modify.
1377
modAttrs = null;
1378    modAttrsParameter =
1379         parameters.getMultiLineTextParameter(modAttrsParameter.getName());
1380    if ((modAttrsParameter != null) && (modAttrsParameter.hasValue()))
1381    {
1382      modAttrs = modAttrsParameter.getNonBlankLines();
1383    }
1384
1385    // Determine whether to skip the bind attempt.
1386
skipBind = false;
1387    skipBindParameter =
1388         parameters.getBooleanParameter(skipBindParameter.getName());
1389    if (skipBindParameter != null)
1390    {
1391      skipBind = skipBindParameter.getBooleanValue();
1392    }
1393
1394    // Get the warm up time.
1395
warmUpTime = 0;
1396    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1397    if (warmUpParameter != null)
1398    {
1399      warmUpTime = warmUpParameter.getIntValue();
1400    }
1401
1402    // Get the cool down time.
1403
coolDownTime = 0;
1404    coolDownParameter =
1405         parameters.getIntegerParameter(coolDownParameter.getName());
1406    if (coolDownParameter != null)
1407    {
1408      coolDownTime = coolDownParameter.getIntValue();
1409    }
1410
1411    // Get the max operation time limit.
1412
timeLimitParameter =
1413         parameters.getIntegerParameter(timeLimitParameter.getName());
1414    if (timeLimitParameter != null)
1415    {
1416      timeLimit = timeLimitParameter.getIntValue();
1417    }
1418
1419    // Get the delay between authentication attempts.
1420
delay = 0;
1421    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1422    if (delayParameter != null)
1423    {
1424      delay = delayParameter.getIntValue();
1425    }
1426
1427    // Get the flag indicating whether we should use SSL or not
1428
useSSL = false;
1429    useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
1430    if (useSSLParameter != null)
1431    {
1432      useSSL = useSSLParameter.getBooleanValue();
1433    }
1434
1435    // If we are to use SSL, then get all the other SSL-related info
1436
if (useSSL)
1437    {
1438      // Whether to blindly trust any SSL certificate
1439
blindTrustParameter =
1440           parameters.getBooleanParameter(blindTrustParameter.getName());
1441      if (blindTrustParameter != null)
1442      {
1443        blindTrust = blindTrustParameter.getBooleanValue();
1444      }
1445
1446      // The location of the JSSE key store
1447
sslKeyStore = null;
1448      keyStoreParameter =
1449           parameters.getStringParameter(keyStoreParameter.getName());
1450      if ((keyStoreParameter != null) && (keyStoreParameter.hasValue()))
1451      {
1452        sslKeyStore = keyStoreParameter.getStringValue();
1453        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1454      }
1455
1456      // The JSSE key store password
1457
sslKeyPassword = null;
1458      keyPWParameter =
1459           parameters.getPasswordParameter(keyPWParameter.getName());
1460      if ((keyPWParameter != null) && (keyPWParameter.hasValue()))
1461      {
1462        sslKeyPassword = keyPWParameter.getStringValue();
1463        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPassword);
1464      }
1465
1466      // The location of the JSSE trust store
1467
sslTrustStore = null;
1468      trustStoreParameter =
1469           parameters.getStringParameter(trustStoreParameter.getName());
1470      if ((trustStoreParameter != null) && (trustStoreParameter.hasValue()))
1471      {
1472        sslTrustStore = trustStoreParameter.getStringValue();
1473        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1474      }
1475
1476      // The JSSE trust store password
1477
sslTrustPassword = null;
1478      trustPWParameter =
1479           parameters.getPasswordParameter(trustPWParameter.getName());
1480      if ((trustPWParameter != null) && (trustPWParameter.hasValue()))
1481      {
1482        sslTrustPassword = trustPWParameter.getStringValue();
1483        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPassword);
1484      }
1485    }
1486
1487
1488    // Get the indicator that specifies whether to ignore invalid credentials
1489
// errors.
1490
ignoreInvCredParameter =
1491         parameters.getBooleanParameter(ignoreInvCredParameter.getName());
1492    if (ignoreInvCredParameter != null)
1493    {
1494      ignoreInvalidCredentials = ignoreInvCredParameter.getBooleanValue();
1495    }
1496
1497    // Get the indicator that specifies whether to use shared connections.
1498
shareConnsParameter =
1499         parameters.getBooleanParameter(shareConnsParameter.getName());
1500    if (shareConnsParameter != null)
1501    {
1502      useSharedConnections = shareConnsParameter.getBooleanValue();
1503    }
1504
1505
1506    // If we are to use shared connections, then establish them now.
1507
if (useSharedConnections)
1508    {
1509      if (useSSL)
1510      {
1511        if (blindTrust)
1512        {
1513          try
1514          {
1515            sharedAuthConnection =
1516                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1517            sharedBindConnection =
1518                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1519          }
1520          catch (LDAPException le)
1521          {
1522            throw new UnableToRunException(le.getMessage(), le);
1523          }
1524        }
1525        else
1526        {
1527          sharedAuthConnection =
1528               new LDAPConnection(new JSSESocketFactory(null));
1529          sharedBindConnection =
1530               new LDAPConnection(new JSSESocketFactory(null));
1531        }
1532      }
1533      else
1534      {
1535        sharedAuthConnection = new LDAPConnection();
1536        sharedBindConnection = new LDAPConnection();
1537      }
1538
1539      try
1540      {
1541        sharedAuthConnection.connect(3, directoryHost, directoryPort, bindDN,
1542                                     bindPW);
1543        sharedBindConnection.connect(3, directoryHost, directoryPort, "", "");
1544      }
1545      catch (Exception JavaDoc e)
1546      {
1547        throw new UnableToRunException("Could not establish shared " +
1548                                       "connections to the directory: " + e,
1549                                       e);
1550      }
1551    }
1552
1553
1554    // Seed the parent random number generator.
1555
parentRandom = new Random();
1556  }
1557
1558
1559
1560  /**
1561   * Initializes this job class with the information that it will use when
1562   * actually running the job. This will also initialize the stat trackers used
1563   * by the job.
1564   *
1565   * @param clientID The thread ID for this thread.
1566   * @param threadID The thread ID for this thread.
1567   * @param collectionInterval The collection interval to use for gathering
1568   * statistics while processing the job.
1569   * @param parameters The st of parameters that contain the
1570   * information used to customize the way this job
1571   * is processed.
1572   *
1573   * @throws UnableToRunException If a problem occurs that prevents the thread
1574   * from being able to run properly.
1575   */

1576  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1577                               int collectionInterval, ParameterList parameters)
1578         throws UnableToRunException
1579  {
1580    // Seed the random number generator for this thread.
1581
random = new Random(parentRandom.nextLong());
1582
1583    // If we are not going to use shared connections, then create the
1584
// connections for use by this thread. Otherwise, just grab the shared
1585
// connections.
1586
if (useSharedConnections)
1587    {
1588      authConnection = sharedAuthConnection;
1589      bindConnection = sharedBindConnection;
1590    }
1591    else
1592    {
1593      if (useSSL)
1594      {
1595        if (blindTrust)
1596        {
1597          try
1598          {
1599            authConnection =
1600                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1601            bindConnection =
1602                 new LDAPConnection(new JSSEBlindTrustSocketFactory());
1603          }
1604          catch (LDAPException le)
1605          {
1606            throw new UnableToRunException(le.getMessage(), le);
1607          }
1608        }
1609        else
1610        {
1611          authConnection = new LDAPConnection(new JSSESocketFactory(null));
1612          bindConnection = new LDAPConnection(new JSSESocketFactory(null));
1613        }
1614      }
1615      else
1616      {
1617        authConnection = new LDAPConnection();
1618        bindConnection = new LDAPConnection();
1619      }
1620
1621      try
1622      {
1623        authConnection.connect(3, directoryHost, directoryPort, bindDN, bindPW);
1624        bindConnection.connect(3, directoryHost, directoryPort, "", "");
1625      }
1626      catch (Exception JavaDoc e)
1627      {
1628        throw new UnableToRunException("Unable to establish the connections " +
1629                                       "to the directory server: " + e, e);
1630      }
1631    }
1632
1633    // Initialize the constraints.
1634
authConstraints = authConnection.getConstraints();
1635    bindConstraints = bindConnection.getConstraints();
1636    authSearchConstraints = authConnection.getSearchConstraints();
1637    authConstraints.setTimeLimit(1000*timeLimit);
1638    bindConstraints.setTimeLimit(1000*timeLimit);
1639    authSearchConstraints.setTimeLimit(1000*timeLimit);
1640    authSearchConstraints.setServerTimeLimit(timeLimit);
1641
1642
1643    // Create the stat trackers.
1644
attemptCounter =
1645         new IncrementalTracker(clientID, threadID,
1646                                STAT_TRACKER_AUTHENTICATION_ATTEMPTS,
1647                                collectionInterval);
1648    successCounter =
1649         new IncrementalTracker(clientID, threadID,
1650                                STAT_TRACKER_SUCCESSFUL_AUTHENTICATIONS,
1651                                collectionInterval);
1652    failureCounter =
1653         new IncrementalTracker(clientID, threadID,
1654                                STAT_TRACKER_FAILED_AUTHENTICATIONS,
1655                                collectionInterval);
1656    bindCounter = new IncrementalTracker(clientID, threadID,
1657                                         STAT_TRACKER_NUM_BINDS,
1658                                         collectionInterval);
1659    modCounter = new IncrementalTracker(clientID, threadID,
1660                                        STAT_TRACKER_NUM_MODS,
1661                                        collectionInterval);
1662    searchCounter = new IncrementalTracker(clientID, threadID,
1663                                           STAT_TRACKER_NUM_SEARCH,
1664                                           collectionInterval);
1665    authTimer = new TimeTracker(clientID, threadID,
1666                                STAT_TRACKER_AUTHENTICATION_TIME,
1667                                collectionInterval);
1668    bindTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_BIND_TIME,
1669                                collectionInterval);
1670    modTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_TIME,
1671                               collectionInterval);
1672    initialSearchTimer = new TimeTracker(clientID, threadID,
1673                                         STAT_TRACKER_INITIAL_SEARCH_TIME,
1674                                         collectionInterval);
1675    subsequentSearchTimer = new TimeTracker(clientID, threadID,
1676                                            STAT_TRACKER_SUBSEQUENT_SEARCH_TIME,
1677                                            collectionInterval);
1678    failureReasonTracker = new CategoricalTracker(clientID, threadID,
1679                                                  STAT_TRACKER_FAIL_REASON,
1680                                                  collectionInterval);
1681
1682
1683    // Enable real-time reporting of the data for these stat trackers.
1684
RealTimeStatReporter statReporter = getStatReporter();
1685    if (statReporter != null)
1686    {
1687      String JavaDoc jobID = getJobID();
1688      attemptCounter.enableRealTimeStats(statReporter, jobID);
1689      successCounter.enableRealTimeStats(statReporter, jobID);
1690      failureCounter.enableRealTimeStats(statReporter, jobID);
1691      bindCounter.enableRealTimeStats(statReporter, jobID);
1692      modCounter.enableRealTimeStats(statReporter, jobID);
1693      searchCounter.enableRealTimeStats(statReporter, jobID);
1694      authTimer.enableRealTimeStats(statReporter, jobID);
1695      bindTimer.enableRealTimeStats(statReporter, jobID);
1696      modTimer.enableRealTimeStats(statReporter, jobID);
1697      initialSearchTimer.enableRealTimeStats(statReporter, jobID);
1698      subsequentSearchTimer.enableRealTimeStats(statReporter, jobID);
1699    }
1700  }
1701
1702
1703
1704  /**
1705   * Performs the work of actually running the job. When this method completes,
1706   * the job will be done.
1707   */

1708  public void runJob()
1709  {
1710    // Determine the range of time for which we should collect statistics.
1711
long currentTime = System.currentTimeMillis();
1712    boolean collectingStats = false;
1713    long startCollectingTime = currentTime + (1000 * warmUpTime);
1714    long stopCollectingTime = Long.MAX_VALUE;
1715    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1716    {
1717      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1718    }
1719
1720    // Define a variable that will be used to determine how long to sleep
1721
// between attempts.
1722
long authStartTime = 0;
1723
1724
1725    // Loop until it is time to stop.
1726
while (! shouldStop())
1727    {
1728      currentTime = System.currentTimeMillis();
1729      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1730          (currentTime < stopCollectingTime))
1731      {
1732        // Start all the stat trackers.
1733
attemptCounter.startTracker();
1734        successCounter.startTracker();
1735        failureCounter.startTracker();
1736        authTimer.startTracker();
1737        bindCounter.startTracker();
1738        modCounter.startTracker();
1739        searchCounter.startTracker();
1740        bindTimer.startTracker();
1741        modTimer.startTracker();
1742        initialSearchTimer.startTracker();
1743        subsequentSearchTimer.startTracker();
1744        failureReasonTracker.startTracker();
1745        collectingStats = true;
1746      }
1747      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1748      {
1749        attemptCounter.stopTracker();
1750        successCounter.stopTracker();
1751        failureCounter.stopTracker();
1752        authTimer.stopTracker();
1753        bindCounter.stopTracker();
1754        modCounter.stopTracker();
1755        searchCounter.stopTracker();
1756        bindTimer.stopTracker();
1757        modTimer.stopTracker();
1758        initialSearchTimer.stopTracker();
1759        subsequentSearchTimer.stopTracker();
1760        failureReasonTracker.stopTracker();
1761        collectingStats = false;
1762      }
1763
1764      // See if we need to sleep before the next attempt
1765
if ((delay > 0) && (authStartTime > 0))
1766      {
1767        long now = System.currentTimeMillis();
1768        long sleepTime = delay - (now - authStartTime);
1769        if (sleepTime > 0)
1770        {
1771          try
1772          {
1773            Thread.sleep(sleepTime);
1774          } catch (InterruptedException JavaDoc ie) {}
1775
1776          if (shouldStop())
1777          {
1778            break;
1779          }
1780        }
1781      }
1782
1783      // Get a random user number and translate that to a login ID and password.
1784
String JavaDoc[] loginInfo = getLoginInfo();
1785      String JavaDoc loginID = loginInfo[0];
1786      String JavaDoc password = loginInfo[1];
1787
1788
1789      // Start the auth attempt timer now.
1790
if (delay > 0)
1791      {
1792        authStartTime = System.currentTimeMillis();
1793      }
1794
1795
1796      // Increment the number of authentication attempts and start the timer
1797
if (collectingStats)
1798      {
1799        attemptCounter.increment();
1800        authTimer.startTimer();
1801      }
1802
1803      String JavaDoc failureReason = "Search 1";
1804
1805      try
1806      {
1807        // First, issue a search to try to find the user's entry.
1808
String JavaDoc userDN = null;
1809        String JavaDoc filter = "(" + loginIDAttr + "=" + loginID + ")";
1810        LDAPSearchResults results;
1811        if (collectingStats)
1812        {
1813          searchCounter.increment();
1814          initialSearchTimer.startTimer();
1815        }
1816        results = authConnection.search(searchBase, LDAPConnection.SCOPE_SUB,
1817                                        filter, returnAttrsOC, false,
1818                                        authSearchConstraints);
1819        while (results.hasMoreElements())
1820        {
1821          Object JavaDoc element = results.nextElement();
1822          if (element instanceof LDAPEntry)
1823          {
1824            userDN = ((LDAPEntry) element).getDN();
1825          }
1826        }
1827        if (collectingStats)
1828        {
1829          initialSearchTimer.stopTimer();
1830        }
1831
1832        // Make sure that we got a user DN. If not, then it's a failed attempt.
1833
if (userDN == null)
1834        {
1835          if (collectingStats)
1836          {
1837            failureCounter.increment();
1838            authTimer.stopTimer();
1839            failureReasonTracker.increment(failureReason);
1840          }
1841          continue;
1842        }
1843
1844        // Now do a base-level search on the user's entry to retrieve the
1845
// objectClass attribute.
1846
failureReason = "Search 2";
1847        filter = "(objectClass=*)";
1848        if (collectingStats)
1849        {
1850          searchCounter.increment();
1851          subsequentSearchTimer.startTimer();
1852        }
1853        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1854                                        filter, returnAttrsOC, false,
1855                                        authSearchConstraints);
1856        while (results.hasMoreElements())
1857        {
1858          results.nextElement();
1859        }
1860        if (collectingStats)
1861        {
1862          subsequentSearchTimer.stopTimer();
1863        }
1864
1865        // Now bind as the user.
1866
if (! skipBind)
1867        {
1868          failureReason = "Bind";
1869
1870          try
1871          {
1872            if (collectingStats)
1873            {
1874              bindCounter.increment();
1875              bindTimer.startTimer();
1876            }
1877            bindConnection.authenticate(3, userDN, password, bindConstraints);
1878            if (collectingStats)
1879            {
1880              bindTimer.stopTimer();
1881            }
1882          }
1883          catch (LDAPException le)
1884          {
1885            if (collectingStats)
1886            {
1887              bindTimer.stopTimer();
1888            }
1889
1890            if (le.getLDAPResultCode() == LDAPException.INVALID_CREDENTIALS)
1891            {
1892              if (! ignoreInvalidCredentials)
1893              {
1894                if (collectingStats)
1895                {
1896                  failureCounter.increment();
1897                  authTimer.stopTimer();
1898                  failureReasonTracker.increment(failureReason);
1899                }
1900                continue;
1901              }
1902            }
1903            else
1904            {
1905              if (collectingStats)
1906              {
1907                failureCounter.increment();
1908                authTimer.stopTimer();
1909                failureReasonTracker.increment(failureReason);
1910              }
1911              continue;
1912            }
1913          }
1914        }
1915
1916        // Now retrieve the "attr1" attribute from the user's entry.
1917
failureReason = "Search 3";
1918        if (collectingStats)
1919        {
1920          searchCounter.increment();
1921          subsequentSearchTimer.startTimer();
1922        }
1923        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1924                                        filter1, returnAttrs1, false,
1925                                        authSearchConstraints);
1926        while (results.hasMoreElements())
1927        {
1928          results.nextElement();
1929        }
1930        if (collectingStats)
1931        {
1932          subsequentSearchTimer.stopTimer();
1933        }
1934
1935        // Retrieve the "attr2" attribute from the user's entry.
1936
failureReason = "Search 4";
1937        if (collectingStats)
1938        {
1939          searchCounter.increment();
1940          subsequentSearchTimer.startTimer();
1941        }
1942        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1943                                        filter2, returnAttrs2, false,
1944                                        authSearchConstraints);
1945        while (results.hasMoreElements())
1946        {
1947          results.nextElement();
1948        }
1949        if (collectingStats)
1950        {
1951          subsequentSearchTimer.stopTimer();
1952        }
1953
1954        // Retrieve the first attribute again.
1955
failureReason = "Search 5";
1956        if (collectingStats)
1957        {
1958          searchCounter.increment();
1959          subsequentSearchTimer.startTimer();
1960        }
1961        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
1962                                        filter1, returnAttrs1, false,
1963                                        authSearchConstraints);
1964        while (results.hasMoreElements())
1965        {
1966          results.nextElement();
1967        }
1968        if (collectingStats)
1969        {
1970          subsequentSearchTimer.stopTimer();
1971        }
1972
1973        // Perform a modification on the entry
1974
if ((modAttrs != null) && (modAttrs.length > 0))
1975        {
1976          failureReason = "Modify";
1977          LDAPModificationSet modSet = new LDAPModificationSet();
1978          for (int i=0; i < modAttrs.length; i++)
1979          {
1980            LDAPAttribute attr = new LDAPAttribute(modAttrs[i],
1981                                                   getRandomString(80));
1982            modSet.add(LDAPModification.REPLACE, attr);
1983          }
1984          if (collectingStats)
1985          {
1986            modCounter.increment();
1987            modTimer.startTimer();
1988          }
1989          authConnection.modify(userDN, modSet, authConstraints);
1990          if (collectingStats)
1991          {
1992            modTimer.stopTimer();
1993          }
1994        }
1995
1996        // Retrieve the first attribute again.
1997
failureReason = "Search 6";
1998        if (collectingStats)
1999        {
2000          searchCounter.increment();
2001          subsequentSearchTimer.startTimer();
2002        }
2003        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2004                                        filter1, returnAttrs1, false,
2005                                        authSearchConstraints);
2006        while (results.hasMoreElements())
2007        {
2008          results.nextElement();
2009        }
2010        if (collectingStats)
2011        {
2012          subsequentSearchTimer.stopTimer();
2013        }
2014
2015        // Retrieve the first attribute again.
2016
failureReason = "Search 7";
2017        if (collectingStats)
2018        {
2019          searchCounter.increment();
2020          subsequentSearchTimer.startTimer();
2021        }
2022        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2023                                        filter1, returnAttrs1, false,
2024                                        authSearchConstraints);
2025        while (results.hasMoreElements())
2026        {
2027          results.nextElement();
2028        }
2029        if (collectingStats)
2030        {
2031          subsequentSearchTimer.stopTimer();
2032        }
2033
2034        // Retrieve the third attribute.
2035
failureReason = "Search 8";
2036        if (collectingStats)
2037        {
2038          searchCounter.increment();
2039          subsequentSearchTimer.startTimer();
2040        }
2041        results = authConnection.search(userDN, LDAPConnection.SCOPE_BASE,
2042                                        filter3, returnAttrs3, false,
2043                                        authSearchConstraints);
2044        while (results.hasMoreElements())
2045        {
2046          results.nextElement();
2047        }
2048        if (collectingStats)
2049        {
2050          subsequentSearchTimer.stopTimer();
2051        }
2052      }
2053      catch (Exception JavaDoc e)
2054      {
2055
2056        if (collectingStats)
2057        {
2058          failureCounter.increment();
2059          authTimer.stopTimer();
2060          failureReasonTracker.increment(failureReason);
2061        }
2062        continue;
2063      }
2064
2065
2066      // If we have gotten here, then everything is done and we can consider the
2067
// authentication successful.
2068
if (collectingStats)
2069      {
2070        successCounter.increment();
2071        authTimer.stopTimer();
2072      }
2073    }
2074
2075
2076    // Stop all the stat trackers.
2077
if (collectingStats)
2078    {
2079      attemptCounter.stopTracker();
2080      successCounter.stopTracker();
2081      failureCounter.stopTracker();
2082      authTimer.stopTracker();
2083      bindCounter.stopTracker();
2084      modCounter.stopTracker();
2085      searchCounter.stopTracker();
2086      bindTimer.stopTracker();
2087      modTimer.stopTracker();
2088      initialSearchTimer.stopTracker();
2089      subsequentSearchTimer.stopTracker();
2090      failureReasonTracker.stopTracker();
2091    }
2092
2093
2094    // Close the connections to the directory server if appropriate.
2095
if (! useSharedConnections)
2096    {
2097      try
2098      {
2099        authConnection.disconnect();
2100      } catch (Exception JavaDoc e) {}
2101
2102      try
2103      {
2104        bindConnection.disconnect();
2105      } catch (Exception JavaDoc e) {}
2106    }
2107  }
2108
2109
2110
2111  /**
2112   * Attempts to force this thread to exit by closing the connection to the
2113   * directory server and setting it to <CODE>null</CODE>.
2114   */

2115  public void destroy()
2116  {
2117    if (authConnection != null)
2118    {
2119      try
2120      {
2121        authConnection.disconnect();
2122      } catch (Exception JavaDoc e) {}
2123
2124      authConnection = null;
2125    }
2126
2127    if (bindConnection != null)
2128    {
2129      try
2130      {
2131        bindConnection.disconnect();
2132      } catch (Exception JavaDoc e) {}
2133
2134      bindConnection = null;
2135    }
2136  }
2137
2138
2139
2140  /**
2141   * Performs any per-client finalization that should be done for this job. In
2142   * this case, if the job was using shared connections then those connections
2143   * will be closed.
2144   */

2145  public void finalizeClient()
2146  {
2147    // Make sure that the shared connections get closed properly.
2148
if (useSharedConnections)
2149    {
2150      try
2151      {
2152        sharedAuthConnection.disconnect();
2153      } catch (Exception JavaDoc e) {}
2154
2155      try
2156      {
2157        sharedBindConnection.disconnect();
2158      } catch (Exception JavaDoc e) {}
2159    }
2160  }
2161
2162
2163
2164  /**
2165   * Retrieves an array containing the login ID and password that should be
2166   * used to authenticate to the directory.
2167   *
2168   * @return An array containing the login ID and password.
2169   */

2170  public String JavaDoc[] getLoginInfo()
2171  {
2172    String JavaDoc[] loginInfo = new String JavaDoc[2];
2173
2174    if (useDataFile)
2175    {
2176      int slot = (random.nextInt() & 0x7FFFFFFF) % loginIDs.length;
2177      loginInfo[0] = loginIDs[slot];
2178      loginInfo[1] = loginPasswords[slot];
2179    }
2180    else
2181    {
2182      if (useLoginIDRange)
2183      {
2184        int value;
2185        if (useSequential)
2186        {
2187          value = sequentialCounter++;
2188          if (sequentialCounter > loginIDMax)
2189          {
2190            sequentialCounter = loginIDMax;
2191          }
2192        }
2193        else
2194        {
2195          value = ((random.nextInt() & 0x7FFFFFFF) % loginIDSpan) + loginIDMin;
2196        }
2197
2198        loginInfo[0] = loginIDInitial + value + loginIDFinal;
2199        loginInfo[1] = loginPassword;
2200      }
2201      else
2202      {
2203        loginInfo[0] = loginIDInitial;
2204        loginInfo[1] = loginPassword;
2205      }
2206    }
2207
2208    return loginInfo;
2209  }
2210
2211
2212
2213  /**
2214   * Retrieves a string of random characters of the specified length.
2215   *
2216   * @param length The number of characters to include in the string.
2217   *
2218   * @return The generated string of random characters.
2219   */

2220  public String JavaDoc getRandomString(int length)
2221  {
2222    char[] returnArray = new char[length];
2223
2224    for (int i=0; i < returnArray.length; i++)
2225    {
2226      returnArray[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
2227                                ALPHABET.length];
2228    }
2229
2230    return new String JavaDoc(returnArray);
2231  }
2232}
2233
2234
Popular Tags