KickJava   Java API By Example, From Geeks To Geeks.

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


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

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

40 public class LDAPLoadWithReplicaLatencyJobClass
41        extends ReplicaLatencyCheckJobClass
42        implements LDAPRebind
43 {
44   /**
45    * The set of characters that will make up randomly-generated strings.
46    */

47   public static final char[] ALPHABET =
48        "abcdefghijklmnopqrstuvwxyz".toCharArray();
49
50
51
52   /**
53    * The name of the stat tracker that counts the number of attempted adds.
54    */

55   public static final String JavaDoc STAT_TRACKER_ADD_ATTEMPTS = "Add Attempts";
56
57
58
59   /**
60    * The name of the stat tracker that times add operations.
61    */

62   public static final String JavaDoc STAT_TRACKER_ADD_TIME = "Add Time (ms)";
63
64
65
66   /**
67    * The name of the stat tracker that counts the number of attempted compares.
68    */

69   public static final String JavaDoc STAT_TRACKER_COMPARE_ATTEMPTS = "Compare Attempts";
70
71
72
73   /**
74    * The name of the stat tracke that times compare operations.
75    */

76   public static final String JavaDoc STAT_TRACKER_COMPARE_TIME = "Compare Time (ms)";
77
78
79
80   /**
81    * The name of the stat tracker that counts the number of attempted deletes.
82    */

83   public static final String JavaDoc STAT_TRACKER_DELETE_ATTEMPTS = "Delete Attempts";
84
85
86
87   /**
88    * The name of the stat tracker that times delete operations.
89    */

90   public static final String JavaDoc STAT_TRACKER_DELETE_TIME = "Delete Time (ms)";
91
92
93
94   /**
95    * The name of the stat tracker that counts the number of attempted modifies.
96    */

97   public static final String JavaDoc STAT_TRACKER_MODIFY_ATTEMPTS = "Modify Attempts";
98
99
100
101   /**
102    * The name of the stat tracker that times modify operations.
103    */

104   public static final String JavaDoc STAT_TRACKER_MODIFY_TIME = "Modify Time (ms)";
105
106
107
108   /**
109    * The name of the stat tracker that counts the number of attempted modify RDN
110    * operations.
111    */

112   public static final String JavaDoc STAT_TRACKER_MODIFY_RDN_ATTEMPTS =
113        "Modify RDN Attempts";
114
115
116
117   /**
118    * The name of the stat tracker that times modify RDN operations.
119    */

120   public static final String JavaDoc STAT_TRACKER_MODIFY_RDN_TIME =
121        "Modify RDN Time (ms)";
122
123
124
125   /**
126    * The name of the stat tracker that counts the number of attempted
127    * operations.
128    */

129   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS =
130        "Overall Operations Attempted";
131
132
133
134   /**
135    * The name of the stat tracker that categorizes the attempted operations.
136    */

137   public static final String JavaDoc STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY =
138        "Types of Operations Attempted";
139
140
141
142   /**
143    * The name of the stat tracker that times attempted operations.
144    */

145   public static final String JavaDoc STAT_TRACKER_OPERATION_TIME =
146        "Overall Operation Time";
147
148
149
150   /**
151    * The name of the stat tracker that categorizes the result codes received
152    * from the operations.
153    */

154   public static final String JavaDoc STAT_TRACKER_RESULT_CODES = "Result Codes";
155
156
157
158   /**
159    * The name of the stat tracker that counts the number of attempted searches.
160    */

161   public static final String JavaDoc STAT_TRACKER_SEARCH_ATTEMPTS = "Search Attempts";
162
163
164
165   /**
166    * The name of the stat tracker that times search operations.
167    */

168   public static final String JavaDoc STAT_TRACKER_SEARCH_TIME = "Search Time (ms)";
169
170
171
172   /**
173    * The name of the stat tracker that will be used to track replication
174    * latency.
175    */

176   public static final String JavaDoc STAT_TRACKER_REPLICATION_LATENCY =
177        "Replication Latency (ms)";
178
179
180
181   /**
182    * The name of the stat tracker that will be used to categorize latency.
183    */

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

518   public LDAPLoadWithReplicaLatencyJobClass()
519   {
520     super();
521   }
522
523
524
525   /**
526    * Returns the user-friendly name that is to be used for this job
527    * class in the administrative interface.
528    *
529    * @return The user-friendly name for this job class.
530    */

531   public String JavaDoc getJobName()
532   {
533     return "LDAP Load Generator with Replication Latency";
534   }
535
536
537
538   /**
539    * Returns a description of this job that can be seen in the
540    * administrative interface.
541    *
542    * @return A description of this job class.
543    */

544   public String JavaDoc getJobDescription()
545   {
546     return "This job generates various kinds of load against an LDAP " +
547            "directory server while also providing the ability to monitor the " +
548            "replication latency of changes that it makes.";
549   }
550
551
552
553   /**
554    * Retrieves the name of the category in which this job class exists. This is
555    * used to help arrange the job classes in the administrative interface.
556    *
557    * @return The name of the category in which this job class exists.
558    */

559   public String JavaDoc getJobCategoryName()
560   {
561     return "LDAP";
562   }
563
564
565
566   /**
567    * Retrieve a parameter list that can be used to determine all of the
568    * customizeable options that are available for this job.
569    *
570    * @return A parameter list that can be used to determine all of the
571    * customizeable options that are available for this job.
572    */

573   public ParameterList getParameterStubs()
574   {
575     Parameter[] params = new Parameter[]
576     {
577       placeholder,
578       masterHostParameter,
579       masterPortParameter,
580       baseDNParameter,
581       bindDNParameter,
582       bindPasswordParameter,
583       proxyAsDNParameter,
584       placeholder,
585       replicaHostParameter,
586       replicaPortParameter,
587       replicaEntryDNParameter,
588       replicaDelayParameter,
589       placeholder,
590       addFrequencyParameter,
591       compareFrequencyParameter,
592       deleteFrequencyParameter,
593       modifyFrequencyParameter,
594       modifyRDNFrequencyParameter,
595       searchFrequencyParameter,
596       placeholder,
597       dnFileURLParameter,
598       dnParameter,
599       placeholder,
600       filterFileURLParameter,
601       filterParameter,
602       placeholder,
603       attrParameter,
604       placeholder,
605       sizeLimitParameter,
606       timeLimitParameter,
607       warmUpParameter,
608       coolDownParameter,
609       delayParameter,
610       placeholder,
611       cleanUpParameter,
612       disconnectParameter,
613       referralsParameter
614     };
615
616     return new ParameterList(params);
617   }
618
619
620
621   /**
622    * Retrieves the set of stat trackers that will be maintained by this job
623    * class. The stat trackers returned by this method do not have to actually
624    * contain any statistics -- the display name and stat tracker class should
625    * be the only information that callers of this method should rely upon. Note
626    * that this list can be different from the list of statistics actually
627    * collected by the job in some cases (e.g., if the job may not return all the
628    * stat trackers it advertises in all cases, or if the job may return stat
629    * trackers that it did not advertise), but it is a possibility that only the
630    * stat trackers returned by this method will be accessible for some features
631    * in the SLAMD server.
632    *
633    * @param clientID The client ID that should be used for the
634    * returned stat trackers.
635    * @param threadID The thread ID that should be used for the
636    * returned stat trackers.
637    * @param collectionInterval The collection interval that should be used for
638    * the returned stat trackers.
639    *
640    * @return The set of stat trackers that will be maintained by this job
641    * class.
642    */

643   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
644                                            int collectionInterval)
645   {
646     return new StatTracker[]
647     {
648       new IncrementalTracker(clientID, threadID,
649                              STAT_TRACKER_OPERATION_ATTEMPTS,
650                              collectionInterval),
651       new TimeTracker(clientID, threadID, STAT_TRACKER_OPERATION_TIME,
652                       collectionInterval),
653       new IncrementalTracker(clientID, threadID, STAT_TRACKER_ADD_ATTEMPTS,
654                              collectionInterval),
655       new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
656                       collectionInterval),
657       new IncrementalTracker(clientID, threadID, STAT_TRACKER_COMPARE_ATTEMPTS,
658                              collectionInterval),
659       new TimeTracker(clientID, threadID, STAT_TRACKER_COMPARE_TIME,
660                       collectionInterval),
661       new IncrementalTracker(clientID, threadID, STAT_TRACKER_DELETE_ATTEMPTS,
662                              collectionInterval),
663       new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
664                       collectionInterval),
665       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MODIFY_ATTEMPTS,
666                              collectionInterval),
667       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_TIME,
668                       collectionInterval),
669       new IncrementalTracker(clientID, threadID,
670                              STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
671                              collectionInterval),
672       new TimeTracker(clientID, threadID, STAT_TRACKER_MODIFY_RDN_TIME,
673                       collectionInterval),
674       new IncrementalTracker(clientID, threadID, STAT_TRACKER_SEARCH_ATTEMPTS,
675                              collectionInterval),
676       new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME,
677                       collectionInterval),
678       new CategoricalTracker(clientID, threadID,
679                              STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
680                              collectionInterval),
681       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
682                              collectionInterval),
683       new TimeTracker(clientID, threadID, STAT_TRACKER_REPLICATION_LATENCY,
684                       collectionInterval),
685       new CategoricalTracker(clientID, threadID,
686                              STAT_TRACKER_CATEGORIZED_LATENCY,
687                              collectionInterval)
688     };
689   }
690
691
692
693   /**
694    * Retrieves the stat trackers that are maintained for this job thread.
695    *
696    * @return The stat trackers that are maintained for this job thread.
697    */

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

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

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

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

1311  public void initializeClient(String JavaDoc clientID, ParameterList parameters)
1312         throws UnableToRunException
1313  {
1314    // Indicate that no latency tracker thread has yet been chosen.
1315
latencyTrackerChosen = false;
1316
1317
1318    // Get the master directory server address
1319
masterHostParameter =
1320         parameters.getStringParameter(masterHostParameter.getName());
1321    if (masterHostParameter == null)
1322    {
1323      throw new UnableToRunException("No master directory server host " +
1324                                     "provided.");
1325    }
1326    else
1327    {
1328      masterHost = masterHostParameter.getStringValue();
1329    }
1330
1331
1332    // Get the master server port
1333
masterPortParameter =
1334         parameters.getIntegerParameter(masterPortParameter.getName());
1335    if (masterPortParameter != null)
1336    {
1337      masterPort = masterPortParameter.getIntValue();
1338    }
1339
1340
1341    // Get the address of the replica directory server
1342
replicaHost = null;
1343    replicaHostParameter =
1344         parameters.getStringParameter(replicaHostParameter.getName());
1345    if (replicaHostParameter != null)
1346    {
1347      replicaHost = replicaHostParameter.getStringValue();
1348    }
1349
1350
1351    // Get the port for the replica directory server
1352
replicaPort = 389;
1353    replicaPortParameter =
1354         parameters.getIntegerParameter(replicaPortParameter.getName());
1355    if (replicaPortParameter != null)
1356    {
1357      replicaPort = replicaPortParameter.getIntValue();
1358    }
1359
1360
1361    // Get the DN of the entry to use in the latency checks.
1362
replicaEntryDN = null;
1363    replicaEntryDNParameter =
1364         parameters.getStringParameter(replicaEntryDNParameter.getName());
1365    if (replicaEntryDNParameter != null)
1366    {
1367      replicaEntryDN = replicaEntryDNParameter.getStringValue();
1368    }
1369
1370
1371    // Get the delay between latency checks.
1372
latencyDelay = 0;
1373    replicaDelayParameter =
1374         parameters.getIntegerParameter(replicaDelayParameter.getName());
1375    if (replicaDelayParameter != null)
1376    {
1377      latencyDelay = replicaDelayParameter.getIntValue();
1378    }
1379
1380
1381    // Get the base DN.
1382
baseDN = null;
1383    baseDNParameter = parameters.getStringParameter(baseDNParameter.getName());
1384    if ((baseDNParameter != null) && baseDNParameter.hasValue())
1385    {
1386      baseDN = baseDNParameter.getStringValue();
1387
1388    }
1389
1390    // Get the bind DN.
1391
bindDN = "";
1392    bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1393    if ((bindDNParameter != null) && bindDNParameter.hasValue())
1394    {
1395      bindDN = bindDNParameter.getStringValue();
1396    }
1397
1398    // Get the bind password.
1399
bindPW = "";
1400    bindPasswordParameter =
1401         parameters.getPasswordParameter(bindPasswordParameter.getName());
1402    if ((bindPasswordParameter != null) && bindPasswordParameter.hasValue())
1403    {
1404      bindPW = bindPasswordParameter.getStringValue();
1405    }
1406
1407    // Get the proxy as DN.
1408
proxyAsDN = null;
1409    proxyAsDNParameter =
1410         parameters.getStringParameter(proxyAsDNParameter.getName());
1411    if ((proxyAsDNParameter != null) && proxyAsDNParameter.hasValue())
1412    {
1413      proxyAsDNParameter.getStringValue();
1414    }
1415
1416    // Get the add frequency.
1417
addFrequency = 0;
1418    addFrequencyParameter =
1419         parameters.getIntegerParameter(addFrequencyParameter.getName());
1420    if ((addFrequencyParameter != null) && addFrequencyParameter.hasValue())
1421    {
1422      addFrequency = addFrequencyParameter.getIntValue();
1423    }
1424
1425    // Get the compare frequency.
1426
compareFrequency = 0;
1427    compareFrequencyParameter =
1428         parameters.getIntegerParameter(compareFrequencyParameter.getName());
1429    if ((compareFrequencyParameter != null) &&
1430        compareFrequencyParameter.hasValue())
1431    {
1432      compareFrequency = compareFrequencyParameter.getIntValue();
1433    }
1434
1435    // Get the delete frequency.
1436
deleteFrequency = 0;
1437    deleteFrequencyParameter =
1438         parameters.getIntegerParameter(deleteFrequencyParameter.getName());
1439    if ((deleteFrequencyParameter != null) &&
1440        deleteFrequencyParameter.hasValue())
1441    {
1442      deleteFrequency = deleteFrequencyParameter.getIntValue();
1443    }
1444
1445    // Get the modify frequency.
1446
modifyFrequency = 0;
1447    modifyFrequencyParameter =
1448         parameters.getIntegerParameter(modifyFrequencyParameter.getName());
1449    if ((modifyFrequencyParameter != null) &&
1450        modifyFrequencyParameter.hasValue())
1451    {
1452      modifyFrequency = modifyFrequencyParameter.getIntValue();
1453    }
1454
1455    // Get the modify RDN frequency.
1456
modifyRDNFrequency = 0;
1457    modifyRDNFrequencyParameter =
1458         parameters.getIntegerParameter(modifyRDNFrequencyParameter.getName());
1459    if ((modifyRDNFrequencyParameter != null) &&
1460        modifyRDNFrequencyParameter.hasValue())
1461    {
1462      modifyRDNFrequency = modifyRDNFrequencyParameter.getIntValue();
1463    }
1464
1465    // Get the search frequency.
1466
searchFrequency = 0;
1467    searchFrequencyParameter =
1468         parameters.getIntegerParameter(searchFrequencyParameter.getName());
1469    if ((searchFrequencyParameter != null) &&
1470        searchFrequencyParameter.hasValue())
1471    {
1472      searchFrequency = searchFrequencyParameter.getIntValue();
1473    }
1474
1475    // Calculate the total of all the frequencies and create the frequency array
1476
totalFrequency = addFrequency + compareFrequency + deleteFrequency +
1477                     modifyFrequency + modifyRDNFrequency + searchFrequency;
1478    opWeights = new int[6];
1479    opWeights[0] = addFrequency;
1480    opWeights[1] = opWeights[0] + compareFrequency;
1481    opWeights[2] = opWeights[1] + deleteFrequency;
1482    opWeights[3] = opWeights[2] + modifyFrequency;
1483    opWeights[4] = opWeights[3] + modifyRDNFrequency;
1484    opWeights[5] = opWeights[4] + searchFrequency;
1485
1486    // Get the DN or list of DNs to use.
1487
dnFileURLParameter =
1488         parameters.getFileURLParameter(dnFileURLParameter.getName());
1489    if ((dnFileURLParameter != null) && (dnFileURLParameter.hasValue()))
1490    {
1491      try
1492      {
1493        entryDNs = dnFileURLParameter.getNonBlankFileLines();
1494      }
1495      catch (Exception JavaDoc e)
1496      {
1497        throw new UnableToRunException("Unable to retrieve DN list: " + e, e);
1498      }
1499    }
1500    else
1501    {
1502      dnParameter = parameters.getStringParameter(dnParameter.getName());
1503      if ((dnParameter == null) || (! dnParameter.hasValue()))
1504      {
1505        throw new UnableToRunException("No DN file or entry DN specified.");
1506      }
1507
1508      String JavaDoc entryDN = dnParameter.getStringValue();
1509      int openPos = entryDN.indexOf('[');
1510      if (openPos >= 0)
1511      {
1512        int dashPos = entryDN.indexOf('-', openPos);
1513        useDNRange = true;
1514        useSequentialDNs = false;
1515
1516        if (dashPos == 0)
1517        {
1518          dashPos = entryDN.indexOf(':');
1519          useSequentialDNs = true;
1520        }
1521
1522        int closePos = entryDN.indexOf(']', dashPos);
1523        dnMin = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
1524        dnMax = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1525        dnSpan = (dnMax - dnMin) + 1;
1526        dnInitial = entryDN.substring(0, openPos);
1527        dnFinal = entryDN.substring(closePos+1);
1528        nextDN = dnMin;
1529      }
1530      else
1531      {
1532        useDNRange = false;
1533        dnInitial = entryDN;
1534      }
1535    }
1536
1537    // Get the filter or list of filters to use.
1538
filterFileURLParameter =
1539         parameters.getFileURLParameter(filterFileURLParameter.getName());
1540    if ((filterFileURLParameter != null) && (filterFileURLParameter.hasValue()))
1541    {
1542      try
1543      {
1544        searchFilters = filterFileURLParameter.getNonBlankFileLines();
1545      }
1546      catch (Exception JavaDoc e)
1547      {
1548        throw new UnableToRunException("Unable to retrieve filter list: " + e,
1549                                       e);
1550      }
1551    }
1552    else
1553    {
1554      filterParameter =
1555           parameters.getStringParameter(filterParameter.getName());
1556      if ((filterParameter == null) || (! filterParameter.hasValue()))
1557      {
1558        throw new UnableToRunException("No filter file or filter list " +
1559                                       "specified.");
1560      }
1561
1562      String JavaDoc filter = filterParameter.getStringValue();
1563      int openPos = filter.indexOf('[');
1564      if (openPos >= 0)
1565      {
1566        int dashPos = filter.indexOf('-', openPos);
1567        useFilterRange = true;
1568        useSequentialFilters = false;
1569
1570        if (dashPos == 0)
1571        {
1572          dashPos = filter.indexOf(':');
1573          useSequentialFilters = true;
1574        }
1575
1576        int closePos = filter.indexOf(']', dashPos);
1577        filterMin = Integer.parseInt(filter.substring(openPos+1, dashPos));
1578        filterMax = Integer.parseInt(filter.substring(dashPos+1, closePos));
1579        filterSpan = (filterMax - filterMin) + 1;
1580        filterInitial = filter.substring(0, openPos);
1581        filterFinal = filter.substring(closePos+1);
1582        nextFilter = filterMin;
1583      }
1584      else
1585      {
1586        useFilterRange = false;
1587        filterInitial = filter;
1588      }
1589    }
1590
1591    // Get the attribute to compare/modify
1592
attrParameter = parameters.getStringParameter(attrParameter.getName());
1593    if ((attrParameter != null) && attrParameter.hasValue())
1594    {
1595      modAttr = attrParameter.getStringValue();
1596    }
1597
1598    // Get the size limit
1599
sizeLimit = 0;
1600    sizeLimitParameter =
1601         parameters.getIntegerParameter(sizeLimitParameter.getName());
1602    if ((sizeLimitParameter != null) && sizeLimitParameter.hasValue())
1603    {
1604      sizeLimit = sizeLimitParameter.getIntValue();
1605    }
1606
1607    // Get the time limit
1608
timeLimit = 0;
1609    timeLimitParameter =
1610         parameters.getIntegerParameter(timeLimitParameter.getName());
1611    if ((timeLimitParameter != null) && timeLimitParameter.hasValue())
1612    {
1613      timeLimit = timeLimitParameter.getIntValue();
1614    }
1615
1616    // Get the warm-up time.
1617
warmUpTime = 0;
1618    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1619    if ((warmUpParameter != null) && warmUpParameter.hasValue())
1620    {
1621      warmUpTime = warmUpParameter.getIntValue();
1622    }
1623
1624    // Get the cool-down time.
1625
coolDownTime = 0;
1626    coolDownParameter =
1627         parameters.getIntegerParameter(coolDownParameter.getName());
1628    if ((coolDownParameter != null) && coolDownParameter.hasValue())
1629    {
1630      coolDownTime = coolDownParameter.getIntValue();
1631    }
1632
1633    // Get the time between requests
1634
operationDelay = 0;
1635    delayParameter =
1636         parameters.getIntegerParameter(delayParameter.getName());
1637    if ((delayParameter != null) && delayParameter.hasValue())
1638    {
1639      operationDelay = delayParameter.getIntValue();
1640    }
1641
1642    // Determine whether to perform cleanup after the job is done.
1643
cleanUp = true;
1644    cleanUpParameter =
1645         parameters.getBooleanParameter(cleanUpParameter.getName());
1646    if (cleanUpParameter != null)
1647    {
1648      cleanUp = cleanUpParameter.getBooleanValue();
1649    }
1650
1651    // Get the always disconnect flag
1652
alwaysDisconnect = false;
1653    disconnectParameter =
1654         parameters.getBooleanParameter(disconnectParameter.getName());
1655    if (disconnectParameter != null)
1656    {
1657      alwaysDisconnect = disconnectParameter.getBooleanValue();
1658    }
1659
1660    // Get the follow referrals flag
1661
followReferrals = false;
1662    referralsParameter =
1663         parameters.getBooleanParameter(referralsParameter.getName());
1664    if (referralsParameter != null)
1665    {
1666      followReferrals = referralsParameter.getBooleanValue();
1667    }
1668
1669    // Initialize the parent random number generator.
1670
parentRandom = new Random();
1671
1672
1673    // Make sure that the list of DNs to delete is empty.
1674
addedDNs.clear();
1675    dnsToDelete = 0;
1676  }
1677
1678
1679  /**
1680   * Initializes this job thread to be used to actually run the job on the
1681   * client. The provided parameter list should be processed to customize the
1682   * behavior of this job thread, and any other initialization that needs to be
1683   * done in order for the job to run should be performed here as well.
1684   *
1685   * @param clientID The client ID for this job thread.
1686   * @param threadID The thread ID for this job thread.
1687   * @param collectionInterval The length of time in seconds to use as the
1688   * statistics collection interval.
1689   * @param parameters The set of parameters provided to this job that
1690   * can be used to customize its behavior.
1691   *
1692   * @throws UnableToRunException If a problem occurs that prevents the thread
1693   * from being able to run properly.
1694   */

1695  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1696                               int collectionInterval, ParameterList parameters)
1697         throws UnableToRunException
1698  {
1699    // Create all the stat trackers.
1700
addCount = new IncrementalTracker(clientID, threadID,
1701                                            STAT_TRACKER_ADD_ATTEMPTS,
1702                                            collectionInterval);
1703    compareCount = new IncrementalTracker(clientID, threadID,
1704                                            STAT_TRACKER_COMPARE_ATTEMPTS,
1705                                            collectionInterval);
1706    deleteCount = new IncrementalTracker(clientID, threadID,
1707                                            STAT_TRACKER_DELETE_ATTEMPTS,
1708                                            collectionInterval);
1709    modifyCount = new IncrementalTracker(clientID, threadID,
1710                                            STAT_TRACKER_MODIFY_ATTEMPTS,
1711                                            collectionInterval);
1712    modifyRDNCount = new IncrementalTracker(clientID, threadID,
1713                                            STAT_TRACKER_MODIFY_RDN_ATTEMPTS,
1714                                            collectionInterval);
1715    searchCount = new IncrementalTracker(clientID, threadID,
1716                                            STAT_TRACKER_SEARCH_ATTEMPTS,
1717                                            collectionInterval);
1718    operationCount = new IncrementalTracker(clientID, threadID,
1719                                            STAT_TRACKER_OPERATION_ATTEMPTS,
1720                                            collectionInterval);
1721    addTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
1722                                     collectionInterval);
1723    compareTimer = new TimeTracker(clientID, threadID,
1724                                     STAT_TRACKER_COMPARE_TIME,
1725                                     collectionInterval);
1726    deleteTimer = new TimeTracker(clientID, threadID,
1727                                     STAT_TRACKER_DELETE_TIME,
1728                                     collectionInterval);
1729    modifyTimer = new TimeTracker(clientID, threadID,
1730                                     STAT_TRACKER_MODIFY_TIME,
1731                                     collectionInterval);
1732    modifyRDNTimer = new TimeTracker(clientID, threadID,
1733                                     STAT_TRACKER_MODIFY_RDN_TIME,
1734                                     collectionInterval);
1735    searchTimer = new TimeTracker(clientID, threadID,
1736                                     STAT_TRACKER_SEARCH_TIME,
1737                                     collectionInterval);
1738    operationTimer = new TimeTracker(clientID, threadID,
1739                                     STAT_TRACKER_OPERATION_TIME,
1740                                     collectionInterval);
1741    resultCodes = new CategoricalTracker(clientID, threadID,
1742                                            STAT_TRACKER_RESULT_CODES,
1743                                            collectionInterval);
1744    operationTypes =
1745         new CategoricalTracker(clientID, threadID,
1746                                STAT_TRACKER_OPERATION_ATTEMPTS_BY_CATEGORY,
1747                                collectionInterval);
1748
1749
1750    // Enable real-time reporting of the data for these stat trackers.
1751
RealTimeStatReporter statReporter = getStatReporter();
1752    if (statReporter != null)
1753    {
1754      String JavaDoc jobID = getJobID();
1755      addCount.enableRealTimeStats(statReporter, jobID);
1756      compareCount.enableRealTimeStats(statReporter, jobID);
1757      deleteCount.enableRealTimeStats(statReporter, jobID);
1758      modifyCount.enableRealTimeStats(statReporter, jobID);
1759      modifyRDNCount.enableRealTimeStats(statReporter, jobID);
1760      searchCount.enableRealTimeStats(statReporter, jobID);
1761      operationCount.enableRealTimeStats(statReporter, jobID);
1762      addTimer.enableRealTimeStats(statReporter, jobID);
1763      compareTimer.enableRealTimeStats(statReporter, jobID);
1764      deleteTimer.enableRealTimeStats(statReporter, jobID);
1765      modifyTimer.enableRealTimeStats(statReporter, jobID);
1766      modifyRDNTimer.enableRealTimeStats(statReporter, jobID);
1767      searchTimer.enableRealTimeStats(statReporter, jobID);
1768      operationTimer.enableRealTimeStats(statReporter, jobID);
1769    }
1770
1771
1772    // Create the random number generator for this thread
1773
random = new Random(parentRandom.nextLong());
1774
1775
1776    // Initialize the connection to the directory server.
1777
conn = new LDAPConnection();
1778
1779
1780    // See if this thread should be used to report the replica latency
1781
// information. If so, then start the latency check threads.
1782
if ((! latencyTrackerChosen) && (getClientNumber() == 0))
1783    {
1784      latencyCheckMutex = new Object JavaDoc();
1785      latencyTrackerChosen = true;
1786      reportLatencyTracker = true;
1787
1788      // Create the latency timer stat tracker.
1789
latencyTime = new TimeTracker(clientID, threadID,
1790                                    STAT_TRACKER_REPLICATION_LATENCY,
1791                                    collectionInterval);
1792      if (statReporter != null)
1793      {
1794        latencyTime.enableRealTimeStats(statReporter, getJobID());
1795      }
1796
1797      // Create the latency categories stat tracker.
1798
latencyCategories =
1799           new CategoricalTracker(clientID, threadID,
1800                                  STAT_TRACKER_CATEGORIZED_LATENCY,
1801                                  collectionInterval);
1802
1803      // Create the latency thread that will make changes to the master server.
1804
try
1805      {
1806        masterThread =
1807             new LatencyCheckMasterThread(this, masterHost, masterPort, bindDN,
1808                                          bindPW, replicaEntryDN,
1809                                          modAttr, latencyDelay);
1810      }
1811      catch (LDAPException le)
1812      {
1813        throw new UnableToRunException("Could not create the master latency " +
1814                                       "thread: " + le, le);
1815      }
1816
1817      // Create the latency thread that will read changes from the replica.
1818
try
1819      {
1820        replicaThread =
1821             new LatencyCheckReplicaThread(this, replicaHost, replicaPort,
1822                                           bindDN, bindPW,
1823                                           replicaEntryDN);
1824      }
1825      catch (LDAPException le)
1826      {
1827        throw new UnableToRunException("Could not create the replica latency " +
1828                                       "thread: " + le, le);
1829      }
1830
1831      // Start the latency check threads.
1832
masterThread.start();
1833      replicaThread.start();
1834    }
1835    else
1836    {
1837      reportLatencyTracker = false;
1838    }
1839  }
1840
1841
1842
1843  /**
1844   * Perform the work of this job thread by establishing the connection(s) to
1845   * the directory server and issuing all the appropriate queries. The job will
1846   * continue until the specified number of iterations have been performed, the
1847   * stop time has been reached, the maximum duration has been reached, or the
1848   * SLAMD server indicates that a stop has been requested.
1849   */

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

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

2181  public void destroy()
2182  {
2183    if (conn != null)
2184    {
2185      try
2186      {
2187        conn.disconnect();
2188      } catch (Exception JavaDoc e) {}
2189
2190      conn = null;
2191    }
2192
2193    if (masterThread != null)
2194    {
2195      masterThread.masterThread.interrupt();
2196
2197      try
2198      {
2199        masterThread.connection.disconnect();
2200      } catch (Exception JavaDoc e) {}
2201
2202      masterThread.connection = null;
2203      masterThread = null;
2204    }
2205
2206    if (replicaThread != null)
2207    {
2208      replicaThread.replicaThread.interrupt();
2209
2210      try
2211      {
2212        replicaThread.connection.disconnect();
2213      } catch (Exception JavaDoc e) {}
2214
2215      replicaThread.connection = null;
2216      replicaThread = null;
2217    }
2218  }
2219
2220
2221
2222  /**
2223   * Performs an add operation in the directory.
2224   *
2225   * @return The result code of the add operation.
2226   */

2227  public int doAdd()
2228  {
2229    int resultCode = LDAPException.SUCCESS;
2230    LDAPEntry entry = getEntry();
2231    String JavaDoc entryDN = entry.getDN();
2232
2233    if (collectingStats)
2234    {
2235      addCount.increment();
2236      addTimer.startTimer();
2237    }
2238
2239    try
2240    {
2241      conn.add(entry, constraints);
2242      addDNToDelete(entryDN);
2243    }
2244    catch (LDAPException le)
2245    {
2246      resultCode = le.getLDAPResultCode();
2247    }
2248
2249    if (collectingStats)
2250    {
2251      addTimer.stopTimer();
2252    }
2253
2254    return resultCode;
2255  }
2256
2257
2258
2259  /**
2260   * Performs a compare operation in the directory.
2261   *
2262   * @return The result code of the compare operation.
2263   */

2264  public int doCompare()
2265  {
2266    int resultCode;
2267
2268    String JavaDoc dn = getEntryDN();
2269    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2270
2271    if (collectingStats)
2272    {
2273      compareCount.increment();
2274      compareTimer.startTimer();
2275    }
2276
2277    try
2278    {
2279      resultCode = conn.compare(dn, attr, constraints)
2280                   ? LDAPException.COMPARE_TRUE
2281                   : LDAPException.COMPARE_FALSE;
2282    }
2283    catch (LDAPException le)
2284    {
2285      resultCode = le.getLDAPResultCode();
2286    }
2287
2288    if (collectingStats)
2289    {
2290      compareTimer.stopTimer();
2291    }
2292
2293    return resultCode;
2294  }
2295
2296
2297
2298  /**
2299   * Performs a delete operation in the directory.
2300   *
2301   * @return The result code of the delete operation.
2302   */

2303  public int doDelete()
2304  {
2305    int resultCode = LDAPException.SUCCESS;
2306    String JavaDoc dn = getDNToDelete();
2307
2308    if (dn == null)
2309    {
2310      return LDAPException.PARAM_ERROR;
2311    }
2312
2313    if (collectingStats)
2314    {
2315      deleteCount.increment();
2316      deleteTimer.startTimer();
2317    }
2318
2319    try
2320    {
2321      conn.delete(dn, constraints);
2322    }
2323    catch (LDAPException le)
2324    {
2325      resultCode = le.getLDAPResultCode();
2326    }
2327
2328    if (collectingStats)
2329    {
2330      deleteTimer.stopTimer();
2331    }
2332
2333    return resultCode;
2334  }
2335
2336
2337
2338  /**
2339   * Performs a modify operation in the directory.
2340   *
2341   * @return The result code of the modify operation.
2342   */

2343  public int doModify()
2344  {
2345    int resultCode = LDAPException.SUCCESS;
2346    String JavaDoc dn = getEntryDN();
2347    LDAPAttribute attr = new LDAPAttribute(modAttr, getRandomString(80));
2348    LDAPModification mod = new LDAPModification(LDAPModification.REPLACE,
2349                                                       attr);
2350
2351    if (collectingStats)
2352    {
2353      modifyCount.increment();
2354      modifyTimer.startTimer();
2355    }
2356
2357    try
2358    {
2359      conn.modify(dn, mod);
2360    }
2361    catch (LDAPException le)
2362    {
2363      resultCode = le.getLDAPResultCode();
2364    }
2365
2366    if (collectingStats)
2367    {
2368      modifyTimer.stopTimer();
2369    }
2370
2371    return resultCode;
2372  }
2373
2374
2375
2376  /**
2377   * Performs a modify RDN (i.e., rename) operation in the directory.
2378   *
2379   * @return The result code of the modify RDN operation.
2380   */

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

2424  public int doSearch()
2425  {
2426    int resultCode = LDAPException.SUCCESS;
2427    String JavaDoc filter = getSearchFilter();
2428
2429    if (collectingStats)
2430    {
2431      searchCount.increment();
2432      searchTimer.startTimer();
2433    }
2434
2435    try
2436    {
2437      LDAPSearchResults results = conn.search(baseDN, LDAPConnection.SCOPE_SUB,
2438                                              filter, null, false,
2439                                              searchConstraints);
2440      while (results.hasMoreElements())
2441      {
2442        Object JavaDoc element = results.nextElement();
2443      }
2444    }
2445    catch (LDAPException le)
2446    {
2447      resultCode = le.getLDAPResultCode();
2448    }
2449
2450    if (collectingStats)
2451    {
2452      searchTimer.stopTimer();
2453    }
2454
2455    return resultCode;
2456  }
2457
2458
2459
2460  /**
2461   * Retrieves a randomly-generated entry that may be added to the directory.
2462   *
2463   * @return The generated entry.
2464   */

2465  public LDAPEntry getEntry()
2466  {
2467    String JavaDoc randomString = getRandomString(80);
2468
2469    String JavaDoc[] ocValues = new String JavaDoc[]
2470    { "top",
2471      "person",
2472      "organizationalPerson",
2473      "inetOrgPerson"
2474    };
2475
2476    LDAPAttribute[] attrs = new LDAPAttribute[]
2477    {
2478      new LDAPAttribute("objectClass", ocValues),
2479      new LDAPAttribute("uid", randomString),
2480      new LDAPAttribute("givenName", randomString),
2481      new LDAPAttribute("sn", randomString),
2482      new LDAPAttribute("cn", randomString),
2483      new LDAPAttribute("userPassword", randomString)
2484    };
2485
2486    LDAPAttributeSet attrSet = new LDAPAttributeSet(attrs);
2487
2488    return new LDAPEntry("uid=" + randomString + "," + baseDN, attrSet);
2489  }
2490
2491
2492
2493  /**
2494   * Retrieves a randomly-generated string with the specified number of
2495   * characters.
2496   *
2497   * @param length The number of characters to include in the string.
2498   *
2499   * @return The randomly-generated string.
2500   */

2501  public String JavaDoc getRandomString(int length)
2502  {
2503    char[] returnChars = new char[length];
2504
2505    for (int i=0; i < returnChars.length; i++)
2506    {
2507      returnChars[i] = ALPHABET[(random.nextInt() & 0x7FFFFFFF) %
2508                                ALPHABET.length];
2509    }
2510
2511    return new String JavaDoc(returnChars);
2512  }
2513
2514
2515
2516  /**
2517   * Retrieves the DN of an entry on which a compare or modify operation may be
2518   * performed.
2519   *
2520   * @return The DN of an entry on which a compare or modify operation may be
2521   * performed.
2522   */

2523  public String JavaDoc getEntryDN()
2524  {
2525    if (entryDNs == null)
2526    {
2527      if (useDNRange)
2528      {
2529        int value;
2530
2531        if (useSequentialDNs)
2532        {
2533          value = nextDN++;
2534          if (nextDN > dnMax)
2535          {
2536            nextDN = dnMin;
2537          }
2538        }
2539        else
2540        {
2541          value = ((random.nextInt() & 0x7FFFFFFF) % dnSpan) + dnMin;
2542        }
2543
2544        return dnInitial + value + dnFinal;
2545      }
2546      else
2547      {
2548        return dnInitial;
2549      }
2550    }
2551    else
2552    {
2553      return entryDNs[(random.nextInt() & 0x7FFFFFFF) % entryDNs.length];
2554    }
2555  }
2556
2557
2558
2559  /**
2560   * Adds the specified DN to the list of DNs to be deleted and/or renamed.
2561   *
2562   * @param entryDN The DN to be added to the list.
2563   */

2564  public void addDNToDelete(String JavaDoc entryDN)
2565  {
2566    synchronized (addedDNMutex)
2567    {
2568      dnsToDelete++;
2569      addedDNs.add(entryDN);
2570    }
2571  }
2572
2573
2574
2575  /**
2576   * Retrieves the DN of an entry to be deleted or renamed. Delete and modify
2577   * RDN operations will only be performed on entries that have been added.
2578   *
2579   * @return The DN of an entry that can be deleted or renamed. If there are
2580   * no available DNs, then <CODE>null</CODE> will be returned.
2581   */

2582  public String JavaDoc getDNToDelete()
2583  {
2584    synchronized (addedDNMutex)
2585    {
2586      if (dnsToDelete > 0)
2587      {
2588        dnsToDelete--;
2589        return (String JavaDoc) addedDNs.removeFirst();
2590      }
2591    }
2592
2593    return null;
2594  }
2595
2596
2597
2598  /**
2599   * Retrieves a filter that may be used to perform a search.
2600   *
2601   * @return The filter that may be used to perform a search.
2602   */

2603  public String JavaDoc getSearchFilter()
2604  {
2605    if (searchFilters == null)
2606    {
2607      if (useFilterRange)
2608      {
2609        int value;
2610
2611        if (useSequentialFilters)
2612        {
2613          value = nextFilter++;
2614          if (nextFilter > filterMax)
2615          {
2616            nextFilter = filterMin;
2617          }
2618        }
2619        else
2620        {
2621          value = ((random.nextInt() & 0x7FFFFFFF) % filterSpan) + filterMin;
2622        }
2623
2624        return filterInitial + value + filterFinal;
2625      }
2626      else
2627      {
2628        return filterInitial;
2629      }
2630    }
2631    else
2632    {
2633      return searchFilters[(random.nextInt() & 0x7FFFFFFF) %
2634                           searchFilters.length];
2635    }
2636  }
2637
2638
2639
2640  /**
2641   * Specifies the credentials that will be used to bind to the target server if
2642   * a referral is encountered. In this case, we will always attempt the bind
2643   * using the same credentials used to bind to the original target.
2644   *
2645   * @param host The address of the directory server targeted by the referral.
2646   * @param port The port of the directory server targeted by the referral.
2647   *
2648   * @return The credentials that will be used to bind to the server targeted
2649   * by the referral.
2650   */

2651  public LDAPRebindAuth getRebindAuthentication(String JavaDoc host, int port)
2652  {
2653    return new LDAPRebindAuth(bindDN, bindPW);
2654  }
2655}
2656
2657
Popular Tags