KickJava   Java API By Example, From Geeks To Geeks.

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


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

16 package com.sun.slamd.example;
17
18
19
20 import java.io.*;
21 import java.security.*;
22 import java.util.*;
23 import netscape.ldap.*;
24 import netscape.ldap.controls.*;
25 import netscape.ldap.factory.*;
26 import com.sun.slamd.job.*;
27 import com.sun.slamd.parameter.*;
28 import com.sun.slamd.stat.*;
29
30
31
32 /**
33  * This class implements a SLAMD job class that has the ability to generate
34  * various kinds of load against an LDAP directory server. It can perform
35  * search, compare, add, delete, modify, and modify RDN operations. The
36  * relative frequencies of each kind of operation may be specified by the user
37  * scheduling the job for execution. It can also use a weighting mechanism to
38  * target one set of entries more frequently than another, and this weighting
39  * can differ based on the type of operation to perform (i.e., one weighting for
40  * searches and another for modifies and compares). Adds, deletes, and modify
41  * DN operations will not be impacted.
42  *
43  *
44  * @author Neil A. Wilson
45  */

46 public class WeightedLDAPLoadJobClass
47        extends JobClass
48        implements LDAPRebind
49 {
50   /**
51    * The set of characters that will make up randomly-generated strings.
52    */

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

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

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

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

85   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
86        "javax.net.ssl.trustStorePassword";
87
88
89
90   /**
91    * The name of the stat tracker that counts the number of attempted adds.
92    */

93   public static final String JavaDoc STAT_TRACKER_ADD_ATTEMPTS = "Add Attempts";
94
95
96
97   /**
98    * The name of the stat tracker that times add operations.
99    */

100   public static final String JavaDoc STAT_TRACKER_ADD_TIME = "Add Time (ms)";
101
102
103
104   /**
105    * The name of the stat tracker that counts the number of attempted compares.
106    */

107   public static final String JavaDoc STAT_TRACKER_COMPARE_ATTEMPTS = "Compare Attempts";
108
109
110
111   /**
112    * The name of the stat tracke that times compare operations.
113    */

114   public static final String JavaDoc STAT_TRACKER_COMPARE_TIME = "Compare Time (ms)";
115
116
117
118   /**
119    * The name of the stat tracker that counts the number of attempted deletes.
120    */

121   public static final String JavaDoc STAT_TRACKER_DELETE_ATTEMPTS = "Delete Attempts";
122
123
124
125   /**
126    * The name of the stat tracker that times delete operations.
127    */

128   public static final String JavaDoc STAT_TRACKER_DELETE_TIME = "Delete Time (ms)";
129
130
131
132   /**
133    * The name of the stat tracker that counts the number of attempted modifies.
134    */

135   public static final String JavaDoc STAT_TRACKER_MODIFY_ATTEMPTS = "Modify Attempts";
136
137
138
139   /**
140    * The name of the stat tracker that times modify operations.
141    */

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

150   public static final String JavaDoc STAT_TRACKER_MODIFY_RDN_ATTEMPTS =
151        "Modify RDN Attempts";
152
153
154
155   /**
156    * The name of the stat tracker that times modify RDN operations.
157    */

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

167   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS =
168        "Overall Operations Attempted";
169
170
171
172   /**
173    * The name of the stat tracker that categorizes the attempted operations.
174    */

175   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY =
176        "Types of Operations Attempted";
177
178
179
180   /**
181    * The name of the stat tracker that times attempted operations.
182    */

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

192   public static final String JavaDoc STAT_TRACKER_RESULT_CODES = "Result Codes";
193
194
195
196   /**
197    * The name of the stat tracker that counts the number of attempted searches.
198    */

199   public static final String JavaDoc STAT_TRACKER_SEARCH_ATTEMPTS = "Search Attempts";
200
201
202
203   /**
204    * The name of the stat tracker that times search operations.
205    */

206   public static final String JavaDoc STAT_TRACKER_SEARCH_TIME = "Search Time (ms)";
207
208
209
210   /**
211    * The display name of the stat tracker that will be used to track the
212    * percentages of each type of DN used.
213    */

214   public static final String JavaDoc STAT_TRACKER_DN_PERCENTAGES =
215        "DN Percentages";
216
217
218
219   /**
220    * The display name of the stat tracker that will be used to track the
221    * percentages of each type of filter used.
222    */

223   public static final String JavaDoc STAT_TRACKER_FILTER_PERCENTAGES =
224        "Filter Percentages";
225
226
227
228   // The parameter that indicates whether the client should trust any SSL cert.
229
BooleanParameter blindTrustParameter =
230     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
231                          "Indicates whether the client should blindly trust " +
232                          "any certificate presented by the server, or " +
233                          "whether the key and trust stores should be used.",
234                          true);
235
236   // The parameter that indicates whether the job should clean up any entries
237
// that may have been added during processing.
238
BooleanParameter cleanUpParameter =
239        new BooleanParameter("cleanup", "Clean Up When Done",
240                             "Indicates whether each client should clean up " +
241                             "any entries that may have been added during " +
242                             "processing that have not yet been removed.", true);
243
244   // The parameter that indicates whether to disconnect after each operation.
245
BooleanParameter disconnectParameter =
246        new BooleanParameter("disconnect", "Always Disconnect",
247                             "Indicates whether to close and re-establish the " +
248                             "connection to the directory server after each " +
249                             "operation.", false);
250
251   // The parameter that indicates whether to follow referrals.
252
BooleanParameter referralsParameter =
253        new BooleanParameter("follow_referrals", "Follow Referrals",
254                             "Indicates whether to follow referrals " +
255                             "encountered while performing operations in the " +
256                             "directory.", false);
257
258   // The parameter that indicates whether to use SSL when communicating with the
259
// directory server.
260
BooleanParameter useSSLParameter =
261        new BooleanParameter("use_ssl", "Use SSL",
262                             "Indicates whether to use SSL when communicating " +
263                             "with the directory server.", false);
264
265   // The parameter that specifies the frequency for add operations.
266
IntegerParameter addFrequencyParameter =
267     new IntegerParameter("add_frequency", "Add Operation Frequency",
268                          "Specifies the frequency with which adds should be " +
269                          "performed relative to the other types of operations.",
270                          true, 0, true, 0, false, 0);
271
272   // The parameter that specifies the frequency for compare operations.
273
IntegerParameter compareFrequencyParameter =
274        new IntegerParameter("compare_frequency", "Compare Operation Frequency",
275                             "Specifies the frequency with which compares " +
276                             "should be performed relative to the other types " +
277                             "of operations.", true, 0, true, 0, false, 0);
278
279   // The parmeter that specifies the cool-down time in seconds.
280
IntegerParameter coolDownParameter =
281        new IntegerParameter("cool_down", "Cool Down Time",
282                             "The time in seconds that the job should " +
283                             "continue running after ending statistics " +
284                             "collection.", true, 0, true, 0, false, 0);
285
286   // The parameter that specifies the delay between requests.
287
IntegerParameter delayParameter =
288        new IntegerParameter("request_delay", "Time Between Requests (ms)",
289                             "Specifies the length of time in milliseconds " +
290                             "that will pass between requests. Note that " +
291                             "is the time between requests and not the time " +
292                             "between the end of one operation and the " +
293                             "beginning of the next. If any operation takes " +
294                             "longer than this length of time, then there " +
295                             "will be no delay before the start of the next " +
296                             "operation.", false, 0, true, 0, false, 0);
297
298   // The parameter that specifies the frequency for delete operations.
299
IntegerParameter deleteFrequencyParameter =
300        new IntegerParameter("delete_frequency", "Delete Operation Frequency",
301                             "Specifies the frequency with which deletes " +
302                             "should be performed relative to the other types " +
303                             "of operations.", true, 0, true, 0, false, 0);
304
305   // The parameter that specifies the percentage of the time that a DN from the
306
// first range should be used.
307
IntegerParameter dn1PercentageParameter =
308     new IntegerParameter("dn_1_percentage", "DN 1 Percentage",
309                          "Specifies the percentage of modify and compare " +
310                          "operations that should use a DN from the first " +
311                          "range.", true, 50, true, 0, true, 100);
312
313   // The parameter that specifies the percentage of the time that a filter from
314
// the first range should be used.
315
IntegerParameter filter1PercentageParameter =
316     new IntegerParameter("filter_1_percentage", "Filter 1 Percentage",
317                          "Specifies the percentage of search operations that " +
318                          "should use a filter from the first range.", true, 50,
319                          true, 0, true, 100);
320
321   // The parameter that specifies the frequency for modify operations.
322
IntegerParameter modifyFrequencyParameter =
323        new IntegerParameter("modify_frequency", "Modify Operation Frequency",
324                             "Specifies the frequency with which modifies " +
325                             "should be performed relative to the other types " +
326                             "of operations.", true, 0, true, 0, false, 0);
327
328   // The parameter that specifies the frequency for modify RDN operations.
329
IntegerParameter modifyRDNFrequencyParameter =
330        new IntegerParameter("modify_rdn_frequency",
331                             "Modify RDN Operation Frequency",
332                             "Specifies the frequency with which modify RDNs " +
333                             "should be performed relative to the other types " +
334                             "of operations.", true, 0, true, 0, false, 0);
335
336   // The parameter that specifies the port number for the directory server.
337
IntegerParameter portParameter =
338        new IntegerParameter("ldap_port", "Directory Server Port",
339                             "Specifies the port number for the directory " +
340                             "server.", true, 389, true, 1, true, 65535);
341
342   // The parameter that specifies the frequency for search operations.
343
IntegerParameter searchFrequencyParameter =
344        new IntegerParameter("Search_frequency", "Search Operation Frequency",
345                             "Specifies the frequency with which compares " +
346                             "should be performed relative to the other types " +
347                             "of operations.", true, 0, true, 0, false, 0);
348
349   // The parameter that specifies the maximum number of entries that should be
350
// returned from a single search operation.
351
IntegerParameter sizeLimitParameter =
352        new IntegerParameter("size_limit", "Search Size Limit",
353                             "Specifies the maximum number of entries that " +
354                             "should be returned from a single search " +
355                             "operation. A size limit of zero indicates that " +
356                             "there is no limit.", false, 0, true, 0, false, 0);
357
358   // The parameter that specifies the maximum length of time in seconds that any
359
// operation will be allowed to take before being abandoned.
360
IntegerParameter timeLimitParameter =
361        new IntegerParameter("time_limit", "Operation Time Limit",
362                             "Specifies the maximum length of time in seconds " +
363                             "will be allowed for any single operation. If " +
364                             "operation takes longer than this length of time " +
365                             "it will be abandoned. A time limit of zero " +
366                             "indicates that there is no time limit.", false, 0,
367                             true, 0, false, 0);
368
369   // The parmeter that specifies the warm-up time in seconds.
370
IntegerParameter warmUpParameter =
371        new IntegerParameter("warm_up", "Warm Up Time",
372                             "The time in seconds that the job should run " +
373                             "before beginning statistics collection.",
374                             true, 0, true, 0, false, 0);
375
376   // The parameter that specifies the password to use when binding to the
377
// directory server.
378
PasswordParameter bindPasswordParameter =
379        new PasswordParameter("bind_pw", "Bind Password",
380                              "Specifies the password to use when binding to " +
381                              "the directory server. If no password is " +
382                              "specified, then the bind will be performed " +
383                              "anonymously.", false, "");
384
385   // The parameter that specifies the password to access the SSL key store.
386
PasswordParameter sslKeyPWParameter =
387        new PasswordParameter("ssl_key_pw", "SSL Key Store Password",
388                              "Specifies the password to use when accessing " +
389                              "the JSSE key store. If SSL is not used, then " +
390                              "this does not need to be specified.", false, "");
391
392   // The parameter that specifies the password to access the SSL trust store.
393
PasswordParameter sslTrustPWParameter =
394        new PasswordParameter("ssl_trust_pw", "SSL Trust Store Password",
395                              "Specifies the password to use when accessing " +
396                              "the JSSE trust store. If SSL is not used, " +
397                              "then this does not need to be specified.", false,
398                              "");
399
400   // A placeholder parameter used to visually group related parameters.
401
PlaceholderParameter placeholder = new PlaceholderParameter();
402
403   // The parameter that specifies the address of the directory server.
404
StringParameter addressParameter =
405        new StringParameter("ldap_host", "Directory Server Address",
406                            "Specifies the address for the directory server.",
407                            true, "");
408
409   // The parameter that specifies the attribute to target for modify and compare
410
// operations.
411
StringParameter attrParameter =
412        new StringParameter("attr", "Attribute to Compare/Modify",
413                            "Specifies the LDAP attribute at which modify and " +
414                            "compare operations will be targeted.", true,
415                            "description");
416
417   // The parameter that specifies the base DN for operations in the directory.
418
StringParameter baseDNParameter =
419        new StringParameter("base_dn", "Directory Base DN",
420                            "Specifies the base DN under which all operations " +
421                            "will be performed in the directory.", true, "");
422
423   // The parameter that specifies the DN to use when binding to the directory.
424
StringParameter bindDNParameter =
425        new StringParameter("bind_dn", "Bind DN",
426                            "Specifies the DN to use when binding to the " +
427                            "directory server for all operations. If no bind " +
428                            "DN is specified, then the bind will be performed " +
429                            "anonymously.", true, "");
430
431   // The parameter that specifies the DN to use when performing operations on
432
// the first range.
433
StringParameter dn1Parameter =
434        new StringParameter("entry_dn_1", "Entry DN 1",
435                            "Specifies the DN at which all non-search " +
436                            "operations for the first range should be " +
437                            "targeted. A range of DNs may be specified by " +
438                            "placing the first and last values in brackets " +
439                            "separated by a dash (e.g., " +
440                            "'uid=user.[1-1000],ou=People,dc=example,dc=com')",
441                            true, "");
442
443   // The parameter that specifies the DN to use when performing operations on
444
// the second range.
445
StringParameter dn2Parameter =
446        new StringParameter("entry_dn_2", "Entry DN 2",
447                            "Specifies the DN at which all non-search " +
448                            "operations for the second range should be " +
449                            "targeted. A range of DNs may be specified by " +
450                            "placing the first and last values in brackets " +
451                            "separated by a dash (e.g., " +
452                            "'uid=user.[1-1000],ou=People,dc=example,dc=com')",
453                            true, "");
454
455   // The parameter that specifies the filter to use when performing search
456
// operations on the first range.
457
StringParameter filter1Parameter =
458        new StringParameter("filter1", "Search Filter 1",
459                            "Specifies the search filter to use for all " +
460                            "search operations targeted at the first range. " +
461                            "A range of filters may be specified by placing " +
462                            "the first and last values in brackets separated " +
463                            "by a dash (e.g., '(uid=user.[1-1000])')", true, "");
464
465   // The parameter that specifies the filter to use when performing search
466
// operations on the second range.
467
StringParameter filter2Parameter =
468        new StringParameter("filter2", "Search Filter 2",
469                            "Specifies the search filter to use for all " +
470                            "search operations targeted at the second range. " +
471                            "A range of filters may be specified by placing " +
472                            "the first and last values in brackets separated " +
473                            "by a dash (e.g., '(uid=user.[1-1000])')", true, "");
474
475   // The parameter that specifies the DN of the user account whose authority
476
// should be used to perform all operations in the directory.
477
StringParameter proxyAsDNParameter =
478        new StringParameter("proxy_as_dn", "Proxy As DN",
479                            "Specifies the DN of the user whose authority is " +
480                            "to be used when performing operations in the " +
481                            "directory. If this value is specified, then the " +
482                            "proxied authorization control will be used and " +
483                            "the user specified in the bind DN must have the " +
484                            "proxy permission in the directory.", false, "");
485
486   // The parameter that specifies the location of the JSSE key store.
487
StringParameter sslKeyStoreParameter =
488        new StringParameter("ssl_key_store", "SSL Key Store",
489                            "Specifies the location of the JSSE key store to " +
490                            "use with SSL. If SSL is not used, then this " +
491                            "value does not need to be specified.", false, "");
492
493   // The parameter that specifies the location of the JSSE trust store.
494
StringParameter sslTrustStoreParameter =
495        new StringParameter("ssl_trust_store", "SSL Trust Store",
496                            "Specifies the location of the JSSE trust store " +
497                            "to use with SSL. If SSL is not used, then this " +
498                            "value does not need to be specified.", false, "");
499
500   // Static variables used to hold the values of the parameters in each client
501
// (or variables related to the values of those parameters).
502
static boolean alwaysDisconnect;
503   static boolean blindTrust;
504   static boolean cleanUp;
505   static boolean followReferrals;
506   static boolean useDN1Range;
507   static boolean useDN2Range;
508   static boolean useFilter1Range;
509   static boolean useFilter2Range;
510   static boolean useSequentialDNs1;
511   static boolean useSequentialDNs2;
512   static boolean useSequentialFilters1;
513   static boolean useSequentialFilters2;
514   static boolean useSSL;
515   static int addFrequency;
516   static int compareFrequency;
517   static int coolDownTime;
518   static int deleteFrequency;
519   static int dn1Max;
520   static int dn2Max;
521   static int dn1Min;
522   static int dn2Min;
523   static int dn1Percentage;
524   static int dn1Span;
525   static int dn2Span;
526   static int filter1Max;
527   static int filter2Max;
528   static int filter1Min;
529   static int filter2Min;
530   static int filter1Percentage;
531   static int filter1Span;
532   static int filter2Span;
533   static int ldapPort;
534   static int modifyFrequency;
535   static int modifyRDNFrequency;
536   static int nextDN1;
537   static int nextDN2;
538   static int nextFilter1;
539   static int nextFilter2;
540   static int operationDelay;
541   static int searchFrequency;
542   static int sizeLimit;
543   static int timeLimit;
544   static int totalFrequency;
545   static int warmUpTime;
546   static int[] opWeights;
547   static Random parentRandom;
548   static String JavaDoc baseDN;
549   static String JavaDoc bindDN;
550   static String JavaDoc bindPW;
551   static String JavaDoc dn1Initial;
552   static String JavaDoc dn2Initial;
553   static String JavaDoc dn1Final;
554   static String JavaDoc dn2Final;
555   static String JavaDoc filter1Initial;
556   static String JavaDoc filter2Initial;
557   static String JavaDoc filter1Final;
558   static String JavaDoc filter2Final;
559   static String JavaDoc ldapHost;
560   static String JavaDoc modAttr;
561   static String JavaDoc proxyAsDN;
562   static String JavaDoc sslKeyPW;
563   static String JavaDoc sslKeyStore;
564   static String JavaDoc sslTrustPW;
565   static String JavaDoc sslTrustStore;
566
567   // Static variables used to keep track of the DNs of all entries added to the
568
// directory. This list will be used for the entries to delete and to rename.
569
static int dnsToDelete = 0;
570   static LinkedList addedDNs = new LinkedList();
571   static Object JavaDoc addedDNMutex = new Object JavaDoc();
572
573   // Instance variables used as the stat trackers.
574
CategoricalTracker operationTypes;
575   CategoricalTracker resultCodes;
576   CategoricalTracker dnPercentages;
577   CategoricalTracker filterPercentages;
578   IncrementalTracker addCount;
579   IncrementalTracker compareCount;
580   IncrementalTracker deleteCount;
581   IncrementalTracker modifyCount;
582   IncrementalTracker modifyRDNCount;
583   IncrementalTracker operationCount;
584   IncrementalTracker searchCount;
585   TimeTracker addTimer;
586   TimeTracker compareTimer;
587   TimeTracker deleteTimer;
588   TimeTracker modifyTimer;
589   TimeTracker modifyRDNTimer;
590   TimeTracker operationTimer;
591   TimeTracker searchTimer;
592
593   // Other instance variables used in this thread.
594
boolean collectingStats;
595   LDAPConnection conn;
596   LDAPConstraints constraints;
597   LDAPSearchConstraints searchConstraints;
598   Random random;
599
600
601
602
603   /**
604    * Creates a new instance of this job thread. This constructor
605    * does not need to do anything other than invoke the constructor
606    * for the superclass.
607     relative*/

608   public WeightedLDAPLoadJobClass()
609   {
610     super();
611   }
612
613
614
615   /**
616    * Returns the user-friendly name that is to be used for this job
617    * class in the administrative interface.
618    *
619    * @return The user-friendly name for this job class.
620    */

621   public String JavaDoc getJobName()
622   {
623     return "LDAP Weighted Load Generator";
624   }
625
626
627
628   /**
629    * Returns a description of this job that can be seen in the
630    * administrative interface.
631    *
632    * @return A description of this job class.
633    */

634   public String JavaDoc getJobDescription()
635   {
636     return "This job generates various kinds of load against an LDAP " +
637            "directory server using a weighted access pattern.";
638   }
639
640
641
642   /**
643    * Retrieves the name of the category in which this job class exists. This is
644    * used to help arrange the job classes in the administrative interface.
645    *
646    * @return The name of the category in which this job class exists.
647    */

648   public String JavaDoc getJobCategoryName()
649   {
650     return "LDAP";
651   }
652
653
654
655   /**
656    * Retrieve a parameter list that can be used to determine all of the
657    * customizeable options that are available for this job.
658    *
659    * @return A parameter list that can be used to determine all of the
660    * customizeable options that are available for this job.
661    */

662   public ParameterList getParameterStubs()
663   {
664     Parameter[] params = new Parameter[]
665     {
666       placeholder,
667       addressParameter,
668       portParameter,
669       baseDNParameter,
670       bindDNParameter,
671       bindPasswordParameter,
672       proxyAsDNParameter,
673       placeholder,
674       addFrequencyParameter,
675       compareFrequencyParameter,
676       deleteFrequencyParameter,
677       modifyFrequencyParameter,
678       modifyRDNFrequencyParameter,
679       searchFrequencyParameter,
680       placeholder,
681       dn1Parameter,
682       dn2Parameter,
683       dn1PercentageParameter,
684       placeholder,
685       filter1Parameter,
686       filter2Parameter,
687       filter1PercentageParameter,
688       placeholder,
689       attrParameter,
690       placeholder,
691       sizeLimitParameter,
692       timeLimitParameter,
693       warmUpParameter,
694       coolDownParameter,
695       delayParameter,
696       placeholder,
697       useSSLParameter,
698       blindTrustParameter,
699       sslKeyStoreParameter,
700       sslKeyPWParameter,
701       sslTrustStoreParameter,
702       sslTrustPWParameter,
703       placeholder,
704       cleanUpParameter,
705       disconnectParameter,
706       referralsParameter
707     };
708
709     return new ParameterList(params);
710   }
711
712
713
714   /**
715    * Retrieves the set of stat trackers that will be maintained by this job
716    * class. The stat trackers returned by this method do not have to actually
717    * contain any statistics -- the display name and stat tracker class should
718    * be the only information that callers of this method should rely upon. Note
719    * that this list can be different from the list of statistics actually
720    * collected by the job in some cases (e.g., if the job may not return all the
721    * stat trackers it advertises in all cases, or if the job may return stat
722    * trackers that it did not advertise), but it is a possibility that only the
723    * stat trackers returned by this method will be accessible for some features
724    * in the SLAMD server.
725    *
726    * @param clientID The client ID that should be used for the
727    * returned stat trackers.
728    * @param threadID The thread ID that should be used for the
729    * returned stat trackers.
730    * @param collectionInterval The collection interval that should be used for
731    * the returned stat trackers.
732    *
733    * @return The set of stat trackers that will be maintained by this job
734    * class.
735    */

736   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
737                                            int collectionInterval)
738   {
739     return new StatTracker[]
740     {
741       new IncrementalTracker(clientID, threadID,
742                              STAT_TRACKER_OPERATION_ATTEMPTS,
743                              collectionInterval),
744       new TimeTracker(clientID, threadID, STAT_TRACKER_OPERATION_TIME,
745                       collectionInterval),
746       new IncrementalTracker(clientID, threadID, STAT_TRACKER_ADD_ATTEMPTS,
747                              collectionInterval),
748       new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
749                       collectionInterval),
750       new IncrementalTracker(clientID, threadID, STAT_TRACKER_COMPARE_ATTEMPTS,
751                              collectionInterval),
752       new TimeTracker(clientID, threadID, STAT_TRACKER_COMPARE_TIME,
753                       collectionInterval),
754       new IncrementalTracker(clientID, threadID, STAT_TRACKER_DELETE_ATTEMPTS,
755                              collectionInterval),
756       new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
757                       collectionInterval),
758       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MODIFY_ATTEMPTS,
759                              collectionInterval),
760       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_TIME,
761                       collectionInterval),
762       new IncrementalTracker(clientID, threadID,
763                              STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
764                              collectionInterval),
765       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_RDN_TIME,
766                       collectionInterval),
767       new IncrementalTracker(clientID, threadID, STAT_TRACKER_SEARCH_ATTEMPTS,
768                              collectionInterval),
769       new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME,
770                       collectionInterval),
771       new CategoricalTracker(clientID, threadID,
772                              STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
773                              collectionInterval),
774       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
775                              collectionInterval),
776       new CategoricalTracker(clientID, threadID, STAT_TRACKER_DN_PERCENTAGES,
777                              collectionInterval),
778       new CategoricalTracker(clientID, threadID,
779                              STAT_TRACKER_FILTER_PERCENTAGES,
780                              collectionInterval)
781     };
782   }
783
784
785
786   /**
787    * Retrieves the stat trackers that are maintained for this job thread.
788    *
789    * @return The stat trackers that are maintained for this job thread.
790    */

791   public StatTracker[] getStatTrackers()
792   {
793     ArrayList trackerList = new ArrayList();
794
795     // These will always be added, no matter what.
796
trackerList.add(operationCount);
797     trackerList.add(operationTimer);
798     trackerList.add(operationTypes);
799     trackerList.add(resultCodes);
800
801     if (addCount.getTotalCount() > 0)
802     {
803       trackerList.add(addCount);
804       trackerList.add(addTimer);
805     }
806
807     if (compareCount.getTotalCount() > 0)
808     {
809       trackerList.add(compareCount);
810       trackerList.add(compareTimer);
811     }
812
813     if (deleteCount.getTotalCount() > 0)
814     {
815       trackerList.add(deleteCount);
816       trackerList.add(deleteTimer);
817     }
818
819     if (modifyCount.getTotalCount() > 0)
820     {
821       trackerList.add(modifyCount);
822       trackerList.add(modifyTimer);
823     }
824
825     if (modifyRDNCount.getTotalCount() > 0)
826     {
827       trackerList.add(modifyRDNCount);
828       trackerList.add(modifyRDNTimer);
829     }
830
831     if (searchCount.getTotalCount() > 0)
832     {
833       trackerList.add(searchCount);
834       trackerList.add(searchTimer);
835     }
836
837     if ((compareCount.getTotalCount() > 0) || (modifyCount.getTotalCount() > 0))
838     {
839       trackerList.add(dnPercentages);
840     }
841
842     if (searchCount.getTotalCount() > 0)
843     {
844       trackerList.add(filterPercentages);
845     }
846
847     StatTracker[] trackerArray = new StatTracker[trackerList.size()];
848     trackerList.toArray(trackerArray);
849     return trackerArray;
850   }
851
852
853
854   /**
855    * Provides a means of validating the information used to schedule the job,
856    * including the scheduling information and list of parameters.
857    *
858    * @param numClients The number of clients that should be used to
859    * run the job.
860    * @param threadsPerClient The number of threads that should be created on
861    * each client to run the job.
862    * @param threadStartupDelay The delay in milliseconds that should be used
863    * when starting the client threads.
864    * @param startTime The time that the job should start running.
865    * @param stopTime The time that the job should stop running.
866    * @param duration The maximum length of time in seconds that the
867    * job should be allowed to run.
868    * @param collectionInterval The collection interval that should be used
869    * when gathering statistics for the job.
870    * @param parameters The set of parameters provided to this job that
871    * can be used to customize its behavior.
872    *
873    * @throws InvalidValueException If the provided information is not
874    * appropriate for running this job.
875    */

876   public void validateJobInfo(int numClients, int threadsPerClient,
877                               int threadStartupDelay, Date startTime,
878                               Date stopTime, int duration,
879                               int collectionInterval, ParameterList parameters)
880          throws InvalidValueException
881   {
882     // Make sure that at least one of the frequency parameters was given a
883
// positive value.
884
IntegerParameter addFreqParam =
885          parameters.getIntegerParameter(addFrequencyParameter.getName());
886     if ((addFreqParam != null) && (addFreqParam.getIntValue() > 0))
887     {
888       return;
889     }
890
891     IntegerParameter compareFreqParam =
892          parameters.getIntegerParameter(compareFrequencyParameter.getName());
893     if ((compareFreqParam != null) && (compareFreqParam.getIntValue() > 0))
894     {
895       return;
896     }
897
898     IntegerParameter deleteFreqParam =
899          parameters.getIntegerParameter(deleteFrequencyParameter.getName());
900     if ((deleteFreqParam != null) && (deleteFreqParam.getIntValue() > 0))
901     {
902       return;
903     }
904
905     IntegerParameter modifyFreqParam =
906          parameters.getIntegerParameter(modifyFrequencyParameter.getName());
907     if ((modifyFreqParam != null) && (modifyFreqParam.getIntValue() > 0))
908     {
909       return;
910     }
911
912     IntegerParameter modifyRDNFreqParam =
913          parameters.getIntegerParameter(modifyRDNFrequencyParameter.getName());
914     if ((modifyRDNFreqParam != null) && (modifyRDNFreqParam.getIntValue() > 0))
915     {
916       return;
917     }
918
919     IntegerParameter searchFreqParam =
920          parameters.getIntegerParameter(searchFrequencyParameter.getName());
921     if ((searchFreqParam != null) && (searchFreqParam.getIntValue() > 0))
922     {
923       return;
924     }
925
926     throw new InvalidValueException("At least one operation type must have " +
927                                     "a nonzero frequency.");
928   }
929
930
931
932   /**
933    * Indicates whether this job class implements logic that makes it possible to
934    * test the validity of job parameters before scheduling the job for execution
935    * (e.g., to see if the server is reachable using the information provided).
936    *
937    * @return <CODE>true</CODE> if this job provides a means of testing the job
938    * parameters, or <CODE>false</CODE> if not.
939    */

940   public boolean providesParameterTest()
941   {
942     return true;
943   }
944
945
946
947   /**
948    * Provides a means of testing the provided job parameters to determine
949    * whether they are valid (e.g., to see if the server is reachable) before
950    * scheduling the job for execution. This method will be executed by the
951    * SLAMD server system itself and not by any of the clients.
952    *
953    * @param parameters The job parameters to be tested.
954    * @param outputMessages The lines of output that were generated as part of
955    * the testing process. Each line of output should
956    * be added to this list as a separate string, and
957    * empty strings (but not <CODE>null</CODE> values)
958    * are allowed to provide separation between
959    * different messages. No formatting should be
960    * provided for these messages, however, since they
961    * may be displayed in either an HTML or plain text
962    * interface.
963    *
964    * @return <CODE>true</CODE> if the test completed successfully, or
965    * <CODE>false</CODE> if not. Note that even if the test did not
966    * complete successfully, the user will be presented with a warning
967    * but will still be allowed to schedule the job using the provided
968    * parameters. This is necessary because the parameters may still be
969    * valid even if the server couldn't validate them at the time the
970    * job was scheduled (e.g., if the server wasn't running or could not
971    * be reached by the SLAMD server even though it could be by the
972    * clients).
973    */

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

1294  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1295         throws UnableToRunException
1296  {
1297    // Get the address of the directory server.
1298
ldapHost = null;
1299    addressParameter =
1300         parameters.getStringParameter(addressParameter.getName());
1301    if ((addressParameter != null) && addressParameter.hasValue())
1302    {
1303      ldapHost = addressParameter.getStringValue();
1304    }
1305
1306    // Get the port for the directory server.
1307
ldapPort = 389;
1308    portParameter = parameters.getIntegerParameter(portParameter.getName());
1309    if ((portParameter != null) && portParameter.hasValue())
1310    {
1311      ldapPort = portParameter.getIntValue();
1312    }
1313
1314    // Get the base DN.
1315
baseDN = null;
1316    baseDNParameter = parameters.getStringParameter(baseDNParameter.getName());
1317    if ((baseDNParameter != null) && baseDNParameter.hasValue())
1318    {
1319      baseDN = baseDNParameter.getStringValue();
1320
1321    }
1322
1323    // Get the bind DN.
1324
bindDN = "";
1325    bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1326    if ((bindDNParameter != null) && bindDNParameter.hasValue())
1327    {
1328      bindDN = bindDNParameter.getStringValue();
1329    }
1330
1331    // Get the bind password.
1332
bindPW = "";
1333    bindPasswordParameter =
1334         parameters.getPasswordParameter(bindPasswordParameter.getName());
1335    if ((bindPasswordParameter != null) && bindPasswordParameter.hasValue())
1336    {
1337      bindPW = bindPasswordParameter.getStringValue();
1338    }
1339
1340    // Get the proxy as DN.
1341
proxyAsDN = null;
1342    proxyAsDNParameter =
1343         parameters.getStringParameter(proxyAsDNParameter.getName());
1344    if ((proxyAsDNParameter != null) && proxyAsDNParameter.hasValue())
1345    {
1346      proxyAsDNParameter.getStringValue();
1347    }
1348
1349    // Get the add frequency.
1350
addFrequency = 0;
1351    addFrequencyParameter =
1352         parameters.getIntegerParameter(addFrequencyParameter.getName());
1353    if ((addFrequencyParameter != null) && addFrequencyParameter.hasValue())
1354    {
1355      addFrequency = addFrequencyParameter.getIntValue();
1356    }
1357
1358    // Get the compare frequency.
1359
compareFrequency = 0;
1360    compareFrequencyParameter =
1361         parameters.getIntegerParameter(compareFrequencyParameter.getName());
1362    if ((compareFrequencyParameter != null) &&
1363        compareFrequencyParameter.hasValue())
1364    {
1365      compareFrequency = compareFrequencyParameter.getIntValue();
1366    }
1367
1368    // Get the delete frequency.
1369
deleteFrequency = 0;
1370    deleteFrequencyParameter =
1371         parameters.getIntegerParameter(deleteFrequencyParameter.getName());
1372    if ((deleteFrequencyParameter != null) &&
1373        deleteFrequencyParameter.hasValue())
1374    {
1375      deleteFrequency = deleteFrequencyParameter.getIntValue();
1376    }
1377
1378    // Get the modify frequency.
1379
modifyFrequency = 0;
1380    modifyFrequencyParameter =
1381         parameters.getIntegerParameter(modifyFrequencyParameter.getName());
1382    if ((modifyFrequencyParameter != null) &&
1383        modifyFrequencyParameter.hasValue())
1384    {
1385      modifyFrequency = modifyFrequencyParameter.getIntValue();
1386    }
1387
1388    // Get the modify RDN frequency.
1389
modifyRDNFrequency = 0;
1390    modifyRDNFrequencyParameter =
1391         parameters.getIntegerParameter(modifyRDNFrequencyParameter.getName());
1392    if ((modifyRDNFrequencyParameter != null) &&
1393        modifyRDNFrequencyParameter.hasValue())
1394    {
1395      modifyRDNFrequency = modifyRDNFrequencyParameter.getIntValue();
1396    }
1397
1398    // Get the search frequency.
1399
searchFrequency = 0;
1400    searchFrequencyParameter =
1401         parameters.getIntegerParameter(searchFrequencyParameter.getName());
1402    if ((searchFrequencyParameter != null) &&
1403        searchFrequencyParameter.hasValue())
1404    {
1405      searchFrequency = searchFrequencyParameter.getIntValue();
1406    }
1407
1408    // Calculate the total of all the frequencies and create the frequency array
1409
totalFrequency = addFrequency + compareFrequency + deleteFrequency +
1410                     modifyFrequency + modifyRDNFrequency + searchFrequency;
1411    opWeights = new int[6];
1412    opWeights[0] = addFrequency;
1413    opWeights[1] = opWeights[0] + compareFrequency;
1414    opWeights[2] = opWeights[1] + deleteFrequency;
1415    opWeights[3] = opWeights[2] + modifyFrequency;
1416    opWeights[4] = opWeights[3] + modifyRDNFrequency;
1417    opWeights[5] = opWeights[4] + searchFrequency;
1418
1419    // Get the first DN pattern.
1420
dn1Parameter = parameters.getStringParameter(dn1Parameter.getName());
1421    if (dn1Parameter != null)
1422    {
1423      String JavaDoc entryDN = dn1Parameter.getStringValue();
1424      useDN1Range = true;
1425      useSequentialDNs1 = false;
1426
1427      try
1428      {
1429        int openPos = entryDN.indexOf('[');
1430        int dashPos = entryDN.indexOf('-', openPos);
1431        if (dashPos < 0)
1432        {
1433          dashPos = entryDN.indexOf(':', openPos);
1434          useSequentialDNs1 = true;
1435        }
1436        int closePos = entryDN.indexOf(']', dashPos);
1437
1438        dn1Initial = entryDN.substring(0, openPos);
1439        dn1Final = entryDN.substring(closePos+1);
1440
1441        dn1Min = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
1442        dn1Max = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1443        dn1Span = dn1Max - dn1Min + 1;
1444        nextDN1 = dn1Min;
1445      }
1446      catch (Exception JavaDoc e)
1447      {
1448        useDN1Range = false;
1449        dn1Initial = entryDN;
1450      }
1451    }
1452
1453    // Get the second DN pattern.
1454
dn2Parameter = parameters.getStringParameter(dn2Parameter.getName());
1455    if (dn2Parameter != null)
1456    {
1457      String JavaDoc entryDN = dn2Parameter.getStringValue();
1458      useDN2Range = true;
1459      useSequentialDNs2 = false;
1460
1461      try
1462      {
1463        int openPos = entryDN.indexOf('[');
1464        int dashPos = entryDN.indexOf('-', openPos);
1465        if (dashPos < 0)
1466        {
1467          dashPos = entryDN.indexOf(':', openPos);
1468          useSequentialDNs2 = true;
1469        }
1470        int closePos = entryDN.indexOf(']', dashPos);
1471
1472        dn2Initial = entryDN.substring(0, openPos);
1473        dn2Final = entryDN.substring(closePos+1);
1474
1475        dn2Min = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
1476        dn2Max = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1477        dn2Span = dn2Max - dn2Min + 1;
1478        nextDN2 = dn2Min;
1479      }
1480      catch (Exception JavaDoc e)
1481      {
1482        useDN2Range = false;
1483        dn1Initial = entryDN;
1484      }
1485    }
1486
1487    // Get the weight to use when choosing between DN 1 and DN 2.
1488
dn1Percentage = 50;
1489    dn1PercentageParameter =
1490         parameters.getIntegerParameter(dn1PercentageParameter.getName());
1491    if (dn1PercentageParameter != null)
1492    {
1493      dn1Percentage = dn1PercentageParameter.getIntValue();
1494    }
1495
1496    // Get the first filter pattern.
1497
filter1Parameter =
1498         parameters.getStringParameter(filter1Parameter.getName());
1499    if (filter1Parameter != null)
1500    {
1501      String JavaDoc filter = filter1Parameter.getStringValue();
1502      useFilter1Range = true;
1503      useSequentialFilters1 = false;
1504
1505      try
1506      {
1507        int openPos = filter.indexOf('[');
1508        int dashPos = filter.indexOf('-', openPos);
1509        if (dashPos < 0)
1510        {
1511          dashPos = filter.indexOf(':', openPos);
1512          useSequentialFilters1 = true;
1513        }
1514        int closePos = filter.indexOf(']', dashPos);
1515
1516        filter1Initial = filter.substring(0, openPos);
1517        filter1Final = filter.substring(closePos+1);
1518
1519        filter1Min = Integer.parseInt(filter.substring(openPos+1, dashPos));
1520        filter1Max = Integer.parseInt(filter.substring(dashPos+1, closePos));
1521        filter1Span = filter1Max - filter1Min + 1;
1522        nextFilter1 = filter1Min;
1523      }
1524      catch (Exception JavaDoc e)
1525      {
1526        useFilter1Range = false;
1527        filter1Initial = filter;
1528      }
1529    }
1530
1531    // Get the second filter pattern.
1532
filter2Parameter =
1533         parameters.getStringParameter(filter2Parameter.getName());
1534    if (filter2Parameter != null)
1535    {
1536      String JavaDoc filter = filter2Parameter.getStringValue();
1537      useFilter2Range = true;
1538      useSequentialFilters2 = false;
1539
1540      try
1541      {
1542        int openPos = filter.indexOf('[');
1543        int dashPos = filter.indexOf('-', openPos);
1544        if (dashPos < 0)
1545        {
1546          dashPos = filter.indexOf(':', openPos);
1547          useSequentialFilters2 = true;
1548        }
1549        int closePos = filter.indexOf(']', dashPos);
1550
1551        filter2Initial = filter.substring(0, openPos);
1552        filter2Final = filter.substring(closePos+1);
1553
1554        filter2Min = Integer.parseInt(filter.substring(openPos+1, dashPos));
1555        filter2Max = Integer.parseInt(filter.substring(dashPos+1, closePos));
1556        filter2Span = filter2Max - filter2Min + 1;
1557        nextFilter2 = filter2Min;
1558      }
1559      catch (Exception JavaDoc e)
1560      {
1561        useFilter2Range = false;
1562        filter2Initial = filter;
1563      }
1564    }
1565
1566    // Get the weight to use when choosing between filter 1 and DN 2.
1567
filter1Percentage = 50;
1568    filter1PercentageParameter =
1569         parameters.getIntegerParameter(filter1PercentageParameter.getName());
1570    if (filter1PercentageParameter != null)
1571    {
1572      filter1Percentage = filter1PercentageParameter.getIntValue();
1573    }
1574
1575    // Get the attribute to compare/modify
1576
attrParameter = parameters.getStringParameter(attrParameter.getName());
1577    if ((attrParameter != null) && attrParameter.hasValue())
1578    {
1579      modAttr = attrParameter.getStringValue();
1580    }
1581
1582    // Get the size limit
1583
sizeLimit = 0;
1584    sizeLimitParameter =
1585         parameters.getIntegerParameter(sizeLimitParameter.getName());
1586    if ((sizeLimitParameter != null) && sizeLimitParameter.hasValue())
1587    {
1588      sizeLimit = sizeLimitParameter.getIntValue();
1589    }
1590
1591    // Get the time limit
1592
timeLimit = 0;
1593    timeLimitParameter =
1594         parameters.getIntegerParameter(timeLimitParameter.getName());
1595    if ((timeLimitParameter != null) && timeLimitParameter.hasValue())
1596    {
1597      timeLimit = timeLimitParameter.getIntValue();
1598    }
1599
1600    // Get the warm-up time.
1601
warmUpTime = 0;
1602    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1603    if ((warmUpParameter != null) && warmUpParameter.hasValue())
1604    {
1605      warmUpTime = warmUpParameter.getIntValue();
1606    }
1607
1608    // Get the cool-down time.
1609
coolDownTime = 0;
1610    coolDownParameter =
1611         parameters.getIntegerParameter(coolDownParameter.getName());
1612    if ((coolDownParameter != null) && coolDownParameter.hasValue())
1613    {
1614      coolDownTime = coolDownParameter.getIntValue();
1615    }
1616
1617    // Get the time between requests
1618
operationDelay = 0;
1619    delayParameter =
1620         parameters.getIntegerParameter(delayParameter.getName());
1621    if ((delayParameter != null) && delayParameter.hasValue())
1622    {
1623      operationDelay = delayParameter.getIntValue();
1624    }
1625
1626    // Get the use SSL flag
1627
useSSL = false;
1628    useSSLParameter =
1629         parameters.getBooleanParameter(useSSLParameter.getName());
1630    if (useSSLParameter != null)
1631    {
1632      useSSL = useSSLParameter.getBooleanValue();
1633    }
1634
1635    if (useSSL)
1636    {
1637      // See if we should blindly trust any certificate.
1638
blindTrustParameter =
1639           parameters.getBooleanParameter(blindTrustParameter.getName());
1640      if (blindTrustParameter != null)
1641      {
1642        blindTrust = blindTrustParameter.getBooleanValue();
1643      }
1644
1645      // Get the SSL key store
1646
sslKeyStoreParameter =
1647           parameters.getStringParameter(sslKeyStoreParameter.getName());
1648      if ((sslKeyStoreParameter != null) && sslKeyStoreParameter.hasValue())
1649      {
1650        sslKeyStore = sslKeyStoreParameter.getStringValue();
1651        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1652      }
1653
1654      // Get the SSL key password
1655
sslKeyPWParameter =
1656           parameters.getPasswordParameter(sslKeyPWParameter.getName());
1657      if ((sslKeyPWParameter != null) && sslKeyPWParameter.hasValue())
1658      {
1659        sslKeyPW = sslKeyPWParameter.getStringValue();
1660        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPW);
1661      }
1662
1663      // Get the SSL trust store
1664
sslTrustStoreParameter =
1665           parameters.getStringParameter(sslTrustStoreParameter.getName());
1666      if ((sslTrustStoreParameter != null) && sslTrustStoreParameter.hasValue())
1667      {
1668        sslTrustStore = sslTrustStoreParameter.getStringValue();
1669        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1670      }
1671
1672      // Get the SSL trust password
1673
sslTrustPWParameter =
1674           parameters.getPasswordParameter(sslTrustPWParameter.getName());
1675      if ((sslTrustPWParameter != null) && sslTrustPWParameter.hasValue())
1676      {
1677        sslTrustPW = sslTrustPWParameter.getStringValue();
1678        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPW);
1679      }
1680    }
1681
1682    // Determine whether to perform cleanup after the job is done.
1683
cleanUp = true;
1684    cleanUpParameter =
1685         parameters.getBooleanParameter(cleanUpParameter.getName());
1686    if (cleanUpParameter != null)
1687    {
1688      cleanUp = cleanUpParameter.getBooleanValue();
1689    }
1690
1691    // Get the always disconnect flag
1692
alwaysDisconnect = false;
1693    disconnectParameter =
1694         parameters.getBooleanParameter(disconnectParameter.getName());
1695    if (disconnectParameter != null)
1696    {
1697      alwaysDisconnect = disconnectParameter.getBooleanValue();
1698    }
1699
1700    // Get the follow referrals flag
1701
followReferrals = false;
1702    referralsParameter =
1703         parameters.getBooleanParameter(referralsParameter.getName());
1704    if (referralsParameter != null)
1705    {
1706      followReferrals = referralsParameter.getBooleanValue();
1707    }
1708
1709    // Initialize the parent random number generator.
1710
parentRandom = new Random();
1711
1712
1713    // Make sure that the list of DNs to delete is empty.
1714
addedDNs.clear();
1715    dnsToDelete = 0;
1716  }
1717
1718
1719  /**
1720   * Initializes this job thread to be used to actually run the job on the
1721   * client. The provided parameter list should be processed to customize the
1722   * behavior of this job thread, and any other initialization that needs to be
1723   * done in order for the job to run should be performed here as well.
1724   *
1725   * @param clientID The client ID for this job thread.
1726   * @param threadID The thread ID for this job thread.
1727   * @param collectionInterval The length of time in seconds to use as the
1728   * statistics collection interval.
1729   * @param parameters The set of parameters provided to this job that
1730   * can be used to customize its behavior.
1731   *
1732   * @throws UnableToRunException If a problem occurs that prevents the thread
1733   * from being able to run properly.
1734   */

1735  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1736                               int collectionInterval, ParameterList parameters)
1737         throws UnableToRunException
1738  {
1739    // Create all the stat trackers.
1740
addCount = new IncrementalTracker(clientID, threadID,
1741                                            STAT_TRACKER_ADD_ATTEMPTS,
1742                                            collectionInterval);
1743    compareCount = new IncrementalTracker(clientID, threadID,
1744                                            STAT_TRACKER_COMPARE_ATTEMPTS,
1745                                            collectionInterval);
1746    deleteCount = new IncrementalTracker(clientID, threadID,
1747                                            STAT_TRACKER_DELETE_ATTEMPTS,
1748                                            collectionInterval);
1749    modifyCount = new IncrementalTracker(clientID, threadID,
1750                                            STAT_TRACKER_MODIFY_ATTEMPTS,
1751                                            collectionInterval);
1752    modifyRDNCount = new IncrementalTracker(clientID, threadID,
1753                                            STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
1754                                            collectionInterval);
1755    searchCount = new IncrementalTracker(clientID, threadID,
1756                                            STAT_TRACKER_SEARCH_ATTEMPTS,
1757                                            collectionInterval);
1758    operationCount = new IncrementalTracker(clientID, threadID,
1759                                            STAT_TRACKER_OPERATION_ATTEMPTS,
1760                                            collectionInterval);
1761    addTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
1762                                     collectionInterval);
1763    compareTimer = new TimeTracker(clientID, threadID,
1764                                     STAT_TRACKER_COMPARE_TIME,
1765                                     collectionInterval);
1766    deleteTimer = new TimeTracker(clientID, threadID,
1767                                     STAT_TRACKER_DELETE_TIME,
1768                                     collectionInterval);
1769    modifyTimer = new TimeTracker(clientID, threadID,
1770                                     STAT_TRACKER_MODIFY_TIME,
1771                                     collectionInterval);
1772    modifyRDNTimer = new TimeTracker(clientID, threadID,
1773                                     STAT_TRACKER_MODIFY_RDN_TIME,
1774                                     collectionInterval);
1775    searchTimer = new TimeTracker(clientID, threadID,
1776                                     STAT_TRACKER_SEARCH_TIME,
1777                                     collectionInterval);
1778    operationTimer = new TimeTracker(clientID, threadID,
1779                                     STAT_TRACKER_OPERATION_TIME,
1780                                     collectionInterval);
1781    resultCodes = new CategoricalTracker(clientID, threadID,
1782                                            STAT_TRACKER_RESULT_CODES,
1783                                            collectionInterval);
1784    dnPercentages = new CategoricalTracker(clientID, threadID,
1785                                           STAT_TRACKER_DN_PERCENTAGES,
1786                                           collectionInterval);
1787    filterPercentages = new CategoricalTracker(clientID, threadID,
1788                                               STAT_TRACKER_FILTER_PERCENTAGES,
1789                                               collectionInterval);
1790    operationTypes =
1791         new CategoricalTracker(clientID, threadID,
1792                                STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
1793                                collectionInterval);
1794
1795
1796    // Enable real-time reporting of the data for these stat trackers.
1797
RealTimeStatReporter statReporter = getStatReporter();
1798    if (statReporter != null)
1799    {
1800      String JavaDoc jobID = getJobID();
1801      addCount.enableRealTimeStats(statReporter, jobID);
1802      compareCount.enableRealTimeStats(statReporter, jobID);
1803      deleteCount.enableRealTimeStats(statReporter, jobID);
1804      modifyCount.enableRealTimeStats(statReporter, jobID);
1805      modifyRDNCount.enableRealTimeStats(statReporter, jobID);
1806      searchCount.enableRealTimeStats(statReporter, jobID);
1807      operationCount.enableRealTimeStats(statReporter, jobID);
1808      addTimer.enableRealTimeStats(statReporter, jobID);
1809      compareTimer.enableRealTimeStats(statReporter, jobID);
1810      deleteTimer.enableRealTimeStats(statReporter, jobID);
1811      modifyTimer.enableRealTimeStats(statReporter, jobID);
1812      modifyRDNTimer.enableRealTimeStats(statReporter, jobID);
1813      searchTimer.enableRealTimeStats(statReporter, jobID);
1814      operationTimer.enableRealTimeStats(statReporter, jobID);
1815    }
1816
1817
1818    // Create the random number generator for this thread
1819
random = new Random(parentRandom.nextLong());
1820
1821
1822    // If SSL will be used, then establish an SSL-based connection to the
1823
// directory server. When using JSSE, the first connection always takes
1824
// longer than the subsequent connections, so we want to get that out of the
1825
// way before the job actually starts running.
1826
if (useSSL)
1827    {
1828      try
1829      {
1830        if (blindTrust)
1831        {
1832          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1833        }
1834        else
1835        {
1836          conn = new LDAPConnection(new JSSESocketFactory(null));
1837        }
1838        conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
1839        conn.disconnect();
1840      }
1841      catch (Exception JavaDoc e)
1842      {
1843        throw new UnableToRunException("Unable to establish an SSL-based " +
1844                                       "connection to the directory: " + e, e);
1845      }
1846    }
1847    else
1848    {
1849      conn = new LDAPConnection();
1850    }
1851  }
1852
1853
1854
1855  /**
1856   * Perform the work of this job thread by establishing the connection(s) to
1857   * the directory server and issuing all the appropriate queries. The job will
1858   * continue until the specified number of iterations have been performed, the
1859   * stop time has been reached, the maximum duration has been reached, or the
1860   * SLAMD server indicates that a stop has been requested.
1861   */

1862  public void runJob()
1863  {
1864    // Determine the range of time for which we should collect statistics.
1865
long currentTime = System.currentTimeMillis();
1866    collectingStats = false;
1867    long startCollectingTime = currentTime + (1000 * warmUpTime);
1868    long stopCollectingTime = Long.MAX_VALUE;
1869    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1870    {
1871      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1872    }
1873
1874
1875    // Set a variable that we can use to determine if the connection is alive
1876
boolean connected = false;
1877
1878
1879    // Create a loop that will run for the appropriate length of time.
1880
while (! shouldStop())
1881    {
1882      long opStartTime = System.currentTimeMillis();
1883      if ((! collectingStats) && (opStartTime >= startCollectingTime) &&
1884          (opStartTime <= stopCollectingTime))
1885      {
1886        // Tell the stat trackers that they should start tracking now
1887
addCount.startTracker();
1888        compareCount.startTracker();
1889        deleteCount.startTracker();
1890        modifyCount.startTracker();
1891        modifyRDNCount.startTracker();
1892        searchCount.startTracker();
1893        operationCount.startTracker();
1894        addTimer.startTracker();
1895        compareTimer.startTracker();
1896        deleteTimer.startTracker();
1897        modifyTimer.startTracker();
1898        modifyRDNTimer.startTracker();
1899        searchTimer.startTracker();
1900        operationTimer.startTracker();
1901        operationTypes.startTracker();
1902        resultCodes.startTracker();
1903        dnPercentages.startTracker();
1904        filterPercentages.startTracker();
1905        collectingStats = true;
1906      }
1907      else if ((collectingStats) && (opStartTime >= stopCollectingTime))
1908      {
1909        addCount.stopTracker();
1910        compareCount.stopTracker();
1911        deleteCount.stopTracker();
1912        modifyCount.stopTracker();
1913        modifyRDNCount.stopTracker();
1914        searchCount.stopTracker();
1915        operationCount.stopTracker();
1916        addTimer.stopTracker();
1917        compareTimer.stopTracker();
1918        deleteTimer.stopTracker();
1919        modifyTimer.stopTracker();
1920        modifyRDNTimer.stopTracker();
1921        searchTimer.stopTracker();
1922        operationTimer.stopTracker();
1923        operationTypes.stopTracker();
1924        resultCodes.stopTracker();
1925        dnPercentages.stopTracker();
1926        filterPercentages.stopTracker();
1927        collectingStats = false;
1928      }
1929
1930
1931      // If the connection is currently not connected, then establish it
1932
if (! connected)
1933      {
1934        try
1935        {
1936          conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
1937          connected = true;
1938
1939          // Create the constraints for this connection.
1940
constraints = conn.getConstraints();
1941          constraints.setTimeLimit(1000*timeLimit);
1942          constraints.setRebindProc(this);
1943          constraints.setReferrals(followReferrals);
1944
1945          // Create the search constraints for this connection
1946
searchConstraints = conn.getSearchConstraints();
1947          searchConstraints.setMaxResults(sizeLimit);
1948          searchConstraints.setTimeLimit(1000*timeLimit);
1949          searchConstraints.setServerTimeLimit(timeLimit);
1950          searchConstraints.setRebindProc(this);
1951          searchConstraints.setReferrals(followReferrals);
1952
1953          if ((proxyAsDN != null) && (proxyAsDN.length() > 0))
1954          {
1955            LDAPProxiedAuthControl proxyControl =
1956                 new LDAPProxiedAuthControl(proxyAsDN, true);
1957            constraints.setServerControls(proxyControl);
1958            searchConstraints.setServerControls(proxyControl);
1959          }
1960        }
1961        catch (Exception JavaDoc e)
1962        {
1963          logMessage("ERROR -- Could not connect to " + ldapHost + ":" +
1964                     ldapPort + " (" + e + ") -- aborting thread");
1965          if (collectingStats)
1966          {
1967            if (e instanceof LDAPException)
1968            {
1969              int resultCode = ((LDAPException) e).getLDAPResultCode();
1970              resultCodes.increment(String.valueOf(resultCode));
1971            }
1972            else
1973            {
1974              String JavaDoc category = String.valueOf(LDAPException.CONNECT_ERROR);
1975              resultCodes.increment(category);
1976            }
1977          }
1978          indicateStoppedDueToError();
1979          break;
1980        }
1981      }
1982
1983
1984      // Pick the type of operation to perform and then do it.
1985
int resultCode;
1986      int opType = (random.nextInt() & 0x7FFFFFFF) % totalFrequency;
1987
1988      if (collectingStats)
1989      {
1990        operationCount.increment();
1991        operationTimer.startTimer();
1992      }
1993
1994      if (opType < opWeights[0])
1995      {
1996        if (collectingStats)
1997        {
1998          operationTypes.increment("Add");
1999        }
2000        resultCode = doAdd();
2001      }
2002      else if (opType < opWeights[1])
2003      {
2004        if (collectingStats)
2005        {
2006          operationTypes.increment("Compare");
2007        }
2008        resultCode = doCompare();
2009      }
2010      else if (opType < opWeights[2])
2011      {
2012        if (collectingStats)
2013        {
2014          operationTypes.increment("Delete");
2015        }
2016        resultCode = doDelete();
2017      }
2018      else if (opType < opWeights[3])
2019      {
2020        if (collectingStats)
2021        {
2022          operationTypes.increment("Modify");
2023        }
2024        resultCode = doModify();
2025      }
2026      else if (opType < opWeights[4])
2027      {
2028        if (collectingStats)
2029        {
2030          operationTypes.increment("Modify RDN");
2031        }
2032        resultCode = doModifyRDN();
2033      }
2034      else
2035      {
2036        if (collectingStats)
2037        {
2038          operationTypes.increment("Search");
2039        }
2040        resultCode = doSearch();
2041      }
2042
2043      if (collectingStats)
2044      {
2045        operationTimer.stopTimer();
2046        resultCodes.increment(String.valueOf(resultCode));
2047      }
2048
2049
2050      // See if we need to close the connection to the directory.
2051
if (alwaysDisconnect)
2052      {
2053        try
2054        {
2055          conn.disconnect();
2056        } catch (Exception JavaDoc e) {}
2057        connected = false;
2058      }
2059
2060
2061      // See if we need to sleep until the next operation.
2062
if (operationDelay > 0)
2063      {
2064        long opTime = System.currentTimeMillis() - opStartTime;
2065        if ((opTime < operationDelay) && (! shouldStop()))
2066        {
2067          try
2068          {
2069            Thread.sleep(operationDelay - opTime);
2070          } catch (InterruptedException JavaDoc ie) {}
2071        }
2072      }
2073    }
2074
2075
2076    // If we are still collecting statistics, then stop.
2077
if (collectingStats)
2078    {
2079      addCount.stopTracker();
2080      compareCount.stopTracker();
2081      deleteCount.stopTracker();
2082      modifyCount.stopTracker();
2083      modifyRDNCount.stopTracker();
2084      searchCount.stopTracker();
2085      operationCount.stopTracker();
2086      addTimer.stopTracker();
2087      compareTimer.stopTracker();
2088      deleteTimer.stopTracker();
2089      modifyTimer.stopTracker();
2090      modifyRDNTimer.stopTracker();
2091      searchTimer.stopTracker();
2092      operationTimer.stopTracker();
2093      operationTypes.stopTracker();
2094      dnPercentages.stopTracker();
2095      filterPercentages.stopTracker();
2096      resultCodes.stopTracker();
2097    }
2098
2099
2100    // If we are still connected to the directory, then disconnect.
2101
try
2102    {
2103      conn.disconnect();
2104    } catch (Exception JavaDoc e) {}
2105  }
2106
2107
2108
2109  /**
2110   * Performs any per-client finalization that should be done for this job. In
2111   * this case, it will clean up any entries that may still be left over from
2112   * processing.
2113   */

2114  public void finalizeClient()
2115  {
2116    if (cleanUp)
2117    {
2118      if (useSSL)
2119      {
2120        try
2121        {
2122          if (blindTrust)
2123          {
2124            conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
2125          }
2126          else
2127          {
2128            conn = new LDAPConnection(new JSSESocketFactory(null));
2129          }
2130        }
2131        catch (Exception JavaDoc e)
2132        {
2133          logMessage("Unable to establish an SSL-based connection to the " +
2134                     "directory to perform cleanup: " + e);
2135          return;
2136        }
2137      }
2138      else
2139      {
2140        conn = new LDAPConnection();
2141      }
2142
2143      try
2144      {
2145        conn.connect(3, ldapHost, ldapPort, bindDN, bindPW);
2146      }
2147      catch (Exception JavaDoc e)
2148      {
2149        logMessage("Unable to establish a connection to the directory to " +
2150                   "perform cleanup: " + e);
2151        return;
2152      }
2153
2154      LDAPConstraints constraints = conn.getConstraints();
2155      if (proxyAsDN != null)
2156      {
2157        LDAPProxiedAuthControl proxyControl =
2158             new LDAPProxiedAuthControl(proxyAsDN, true);
2159        constraints.setServerControls(proxyControl);
2160      }
2161
2162
2163      while (! addedDNs.isEmpty())
2164      {
2165        String JavaDoc dnToDelete = (String JavaDoc) addedDNs.removeFirst();
2166
2167        try
2168        {
2169          conn.delete(dnToDelete, constraints);
2170        }
2171        catch (LDAPException le)
2172        {
2173          logMessage("Unable to perform cleanup -- exception thrown while " +
2174                     "trying to delete entry \"" + dnToDelete + "\": " + le);
2175          try
2176          {
2177            conn.disconnect();
2178          } catch (Exception JavaDoc e) {}
2179          return;
2180        }
2181      }
2182
2183      try
2184      {
2185        conn.disconnect();
2186      } catch (Exception JavaDoc e) {}
2187    }
2188  }
2189
2190
2191
2192  /**
2193   * Attempts to force this thread to exit by closing the connection to the
2194   * directory server and setting it to <CODE>null</CODE>.
2195   */

2196  public void destroy()
2197  {
2198    if (conn != null)
2199    {
2200      try
2201      {
2202        conn.disconnect();
2203      } catch (Exception JavaDoc e) {}
2204
2205      conn = null;
2206    }
2207  }
2208
2209
2210
2211  /**
2212   * Performs an add operation in the directory.
2213   *
2214   * @return The result code of the add operation.
2215   */

2216  public int doAdd()
2217  {
2218    int resultCode = LDAPException.SUCCESS;
2219    LDAPEntry entry = getEntry();
2220    String JavaDoc entryDN = entry.getDN();
2221
2222    if (collectingStats)
2223    {
2224      addCount.increment();
2225      addTimer.startTimer();
2226    }
2227
2228    try
2229    {
2230      conn.add(entry, constraints);
2231      addDNToDelete(entryDN);
2232    }
2233    catch (LDAPException le)
2234    {
2235      resultCode = le.getLDAPResultCode();
2236    }
2237
2238    if (collectingStats)
2239    {
2240      addTimer.stopTimer();
2241    }
2242
2243    return resultCode;
2244  }
2245
2246
2247
2248  /**
2249   * Performs a compare operation in the directory.
2250   *
2251   * @return The result code of the compare operation.
2252   */

2253  public int doCompare()
2254  {
2255    int resultCode;
2256
2257    String JavaDoc dn = getEntryDN();
2258    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2259
2260    if (collectingStats)
2261    {
2262      compareCount.increment();
2263      compareTimer.startTimer();
2264    }
2265
2266    try
2267    {
2268      resultCode = conn.compare(dn, attr, constraints)
2269                   ? LDAPException.COMPARE_TRUE
2270                   : LDAPException.COMPARE_FALSE;
2271    }
2272    catch (LDAPException le)
2273    {
2274      resultCode = le.getLDAPResultCode();
2275    }
2276
2277    if (collectingStats)
2278    {
2279      compareTimer.stopTimer();
2280    }
2281
2282    return resultCode;
2283  }
2284
2285
2286
2287  /**
2288   * Performs a delete operation in the directory.
2289   *
2290   * @return The result code of the delete operation.
2291   */

2292  public int doDelete()
2293  {
2294    int resultCode = LDAPException.SUCCESS;
2295    String JavaDoc dn = getDNToDelete();
2296
2297    if (dn == null)
2298    {
2299      return LDAPException.PARAM_ERROR;
2300    }
2301
2302    if (collectingStats)
2303    {
2304      deleteCount.increment();
2305      deleteTimer.startTimer();
2306    }
2307
2308    try
2309    {
2310      conn.delete(dn, constraints);
2311    }
2312    catch (LDAPException le)
2313    {
2314      resultCode = le.getLDAPResultCode();
2315    }
2316
2317    if (collectingStats)
2318    {
2319      deleteTimer.stopTimer();
2320    }
2321
2322    return resultCode;
2323  }
2324
2325
2326
2327  /**
2328   * Performs a modify operation in the directory.
2329   *
2330   * @return The result code of the modify operation.
2331   */

2332  public int doModify()
2333  {
2334    int resultCode = LDAPException.SUCCESS;
2335    String JavaDoc dn = getEntryDN();
2336    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2337    LDAPModification mod = new LDAPModification(LDAPModification.REPLACE,
2338                                                       attr);
2339
2340    if (collectingStats)
2341    {
2342      modifyCount.increment();
2343      modifyTimer.startTimer();
2344    }
2345
2346    try
2347    {
2348      conn.modify(dn, mod);
2349    }
2350    catch (LDAPException le)
2351    {
2352      resultCode = le.getLDAPResultCode();
2353    }
2354
2355    if (collectingStats)
2356    {
2357      modifyTimer.stopTimer();
2358    }
2359
2360    return resultCode;
2361  }
2362
2363
2364
2365  /**
2366   * Performs a modify RDN (i.e., rename) operation in the directory.
2367   *
2368   * @return The result code of the modify RDN operation.
2369   */

2370  public int doModifyRDN()
2371  {
2372    int resultCode = LDAPException.SUCCESS;
2373    String JavaDoc dn = getDNToDelete();
2374    String JavaDoc newRDNValue = getRandomString(80);
2375
2376    if (dn == null)
2377    {
2378      return LDAPException.PARAM_ERROR;
2379    }
2380
2381    if (collectingStats)
2382    {
2383      modifyRDNCount.increment();
2384      modifyRDNTimer.startTimer();
2385    }
2386
2387    try
2388    {
2389
2390      conn.rename(dn, "uid=" + newRDNValue, true, constraints);
2391      addDNToDelete("uid=" + newRDNValue + "," + baseDN);
2392    }
2393    catch (LDAPException le)
2394    {
2395      resultCode = le.getLDAPResultCode();
2396    }
2397
2398    if (collectingStats)
2399    {
2400      modifyRDNTimer.stopTimer();
2401    }
2402
2403    return resultCode;
2404  }
2405
2406
2407
2408  /**
2409   * Performs a search operation in the directory.
2410   *
2411   * @return The result code of the search operation.
2412   */

2413  public int doSearch()
2414  {
2415    int resultCode = LDAPException.SUCCESS;
2416    String JavaDoc filter = getSearchFilter();
2417
2418    if (collectingStats)
2419    {
2420      searchCount.increment();
2421      searchTimer.startTimer();
2422    }
2423
2424    try
2425    {
2426      LDAPSearchResults results = conn.search(baseDN, LDAPConnection.SCOPE_SUB,
2427                                              filter, null, false,
2428                                              searchConstraints);
2429      while (results.hasMoreElements())
2430      {
2431        results.nextElement();
2432      }
2433    }
2434    catch (LDAPException le)
2435    {
2436      resultCode = le.getLDAPResultCode();
2437    }
2438
2439    if (collectingStats)
2440    {
2441      searchTimer.stopTimer();
2442    }
2443
2444    return resultCode;
2445  }
2446
2447
2448
2449  /**
2450   * Retrieves a randomly-generated entry that may be added to the directory.
2451   *
2452   * @return The generated entry.
2453   */

2454  public LDAPEntry getEntry()
2455  {
2456    String JavaDoc randomString = getRandomString(80);
2457
2458    String JavaDoc[] ocValues = new String JavaDoc[]
2459    { "top",
2460      "person",
2461      "organizationalPerson",
2462      "inetOrgPerson"
2463    };
2464
2465    LDAPAttribute[] attrs = new LDAPAttribute[]
2466    {
2467      new LDAPAttribute("objectClass", ocValues),
2468      new LDAPAttribute("uid", randomString),
2469      new LDAPAttribute("givenName", randomString),
2470      new LDAPAttribute("sn", randomString),
2471      new LDAPAttribute("cn", randomString),
2472      new LDAPAttribute("userPassword", randomString)
2473    };
2474
2475    LDAPAttributeSet attrSet = new LDAPAttributeSet(attrs);
2476
2477    return new LDAPEntry("uid=" + randomString + "," + baseDN, attrSet);
2478  }
2479
2480
2481
2482  /**
2483   * Retrieves a randomly-generated string with the specified number of
2484   * characters.
2485   *
2486   * @param length The number of characters to include in the string.
2487   *
2488   * @return The randomly-generated string.
2489   */

2490  public String JavaDoc getRandomString(int length)
2491  {
2492    char[] returnChars = new char[length];
2493
2494    for (int i=0; i < returnChars.length; i++)
2495    {
2496      returnChars[i] = ALPHABET[(random.nextInt() & 0x7FFFFFFF) %
2497                                ALPHABET.length];
2498    }
2499
2500    return new String JavaDoc(returnChars);
2501  }
2502
2503
2504
2505  /**
2506   * Retrieves the DN of an entry on which a compare or modify operation may be
2507   * performed.
2508   *
2509   * @return The DN of an entry on which a compare or modify operation may be
2510   * performed.
2511   */

2512  public String JavaDoc getEntryDN()
2513  {
2514    int percentage = (random.nextInt() & 0x7FFFFFFF) % 100;
2515    if (percentage < dn1Percentage)
2516    {
2517      if (collectingStats)
2518      {
2519        dnPercentages.increment("DN Range 1");
2520      }
2521
2522      if (useDN1Range)
2523      {
2524        int value;
2525
2526        if (useSequentialDNs1)
2527        {
2528          value = nextDN1++;
2529          if (nextDN1 > dn1Max)
2530          {
2531            nextDN1 = dn1Min;
2532          }
2533        }
2534        else
2535        {
2536          value = ((random.nextInt() & 0x7FFFFFFF) % dn1Span) + dn1Min;
2537        }
2538
2539        return dn1Initial + value + dn1Final;
2540      }
2541      else
2542      {
2543        return dn1Initial;
2544      }
2545    }
2546    else
2547    {
2548      if (collectingStats)
2549      {
2550        dnPercentages.increment("DN Range 2");
2551      }
2552
2553      if (useDN2Range)
2554      {
2555        int value;
2556
2557        if (useSequentialDNs2)
2558        {
2559          value = nextDN2++;
2560          if (nextDN2 > dn2Max)
2561          {
2562            nextDN2 = dn2Min;
2563          }
2564        }
2565        else
2566        {
2567          value = ((random.nextInt() & 0x7FFFFFFF) % dn2Span) + dn2Min;
2568        }
2569
2570        return dn2Initial + value + dn2Final;
2571      }
2572      else
2573      {
2574        return dn1Initial;
2575      }
2576    }
2577  }
2578
2579
2580
2581  /**
2582   * Adds the specified DN to the list of DNs to be deleted and/or renamed.
2583   *
2584   * @param entryDN The DN to be added to the list.
2585   */

2586  public void addDNToDelete(String JavaDoc entryDN)
2587  {
2588    synchronized (addedDNMutex)
2589    {
2590      dnsToDelete++;
2591      addedDNs.add(entryDN);
2592    }
2593  }
2594
2595
2596
2597  /**
2598   * Retrieves the DN of an entry to be deleted or renamed. Delete and modify
2599   * RDN operations will only be performed on entries that have been added.
2600   *
2601   * @return The DN of an entry that can be deleted or renamed. If there are
2602   * no available DNs, then <CODE>null</CODE> will be returned.
2603   */

2604  public String JavaDoc getDNToDelete()
2605  {
2606    synchronized (addedDNMutex)
2607    {
2608      if (dnsToDelete > 0)
2609      {
2610        dnsToDelete--;
2611        return (String JavaDoc) addedDNs.removeFirst();
2612      }
2613    }
2614
2615    return null;
2616  }
2617
2618
2619
2620  /**
2621   * Retrieves a filter that may be used to perform a search.
2622   *
2623   * @return The filter that may be used to perform a search.
2624   */

2625  public String JavaDoc getSearchFilter()
2626  {
2627    int percentage = (random.nextInt() & 0x7FFFFFFF) % 100;
2628    if (percentage < dn1Percentage)
2629    {
2630      if (collectingStats)
2631      {
2632        filterPercentages.increment("Search Filter Range 1");
2633      }
2634
2635      if (useFilter1Range)
2636      {
2637        int value;
2638
2639        if (useSequentialFilters1)
2640        {
2641          value = nextFilter1++;
2642          if (nextFilter1 > filter1Max)
2643          {
2644            nextFilter1 = filter1Min;
2645          }
2646        }
2647        else
2648        {
2649          value = ((random.nextInt() & 0x7FFFFFFF) % filter1Span) + filter1Min;
2650        }
2651
2652        return filter1Initial + value + filter1Final;
2653      }
2654      else
2655      {
2656        return filter1Initial;
2657      }
2658    }
2659    else
2660    {
2661      if (collectingStats)
2662      {
2663        filterPercentages.increment("Search Filter Range 2");
2664      }
2665
2666      if (useFilter2Range)
2667      {
2668        int value;
2669
2670        if (useSequentialFilters2)
2671        {
2672          value = nextFilter2++;
2673          if (nextFilter2 > filter2Max)
2674          {
2675            nextFilter2 = filter2Min;
2676          }
2677        }
2678        else
2679        {
2680          value = ((random.nextInt() & 0x7FFFFFFF) % filter2Span) + filter2Min;
2681        }
2682
2683        return filter2Initial + value + filter2Final;
2684      }
2685      else
2686      {
2687        return filter2Initial;
2688      }
2689    }
2690  }
2691
2692
2693
2694  /**
2695   * Specifies the credentials that will be used to bind to the target server if
2696   * a referral is encountered. In this case, we will always attempt the bind
2697   * using the same credentials used to bind to the original target.
2698   *
2699   * @param host The address of the directory server targeted by the referral.
2700   * @param port The port of the directory server targeted by the referral.
2701   *
2702   * @return The credentials that will be used to bind to the server targeted
2703   * by the referral.
2704   */

2705  public LDAPRebindAuth getRebindAuthentication(String JavaDoc host, int port)
2706  {
2707    return new LDAPRebindAuth(bindDN, bindPW);
2708  }
2709}
2710
2711
Popular Tags