KickJava   Java API By Example, From Geeks To Geeks.

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


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 for performing repeated modifications
31  * against an LDAP directory server. All of the configuration for this job
32  * thread can be provided through parameters.
33  *
34  *
35  * @author Neil A. Wilson
36  */

37 public class WeightedModRateWithReplicaLatencyJobClass
38        extends ReplicaLatencyCheckJobClass
39 {
40   /**
41    * The display name for the stat tracker that will be used to track the time
42    * required to perform the first kind of modification.
43    */

44   public static final String JavaDoc STAT_TRACKER_MOD_1_TIME = "Modify DN 1 Time (ms)";
45
46
47
48   /**
49    * The display name for the stat tracker that will be used to track the time
50    * required to perform the second kind of modification.
51    */

52   public static final String JavaDoc STAT_TRACKER_MOD_2_TIME = "Modify DN 2 Time (ms)";
53
54
55
56   /**
57    * The display name for the stat tracker that will be used to track the time
58    * required to perform either kind of modification.
59    */

60   public static final String JavaDoc STAT_TRACKER_MOD_OVERALL_TIME =
61        "Overall Modify Time (ms)";
62
63
64
65   /**
66    * The display name for the stat tracker that will be used to track the number
67    * of the first kind of modifications performed.
68    */

69   public static final String JavaDoc STAT_TRACKER_MOD_1_COUNT =
70        "DN 1 Modifications Performed";
71
72
73
74   /**
75    * The display name for the stat tracker that will be used to track the number
76    * of the second kind of modifications performed.
77    */

78   public static final String JavaDoc STAT_TRACKER_MOD_2_COUNT =
79        "DN 2 Modifications Performed";
80
81
82
83   /**
84    * The display name for the stat tracker that will be used to track the number
85    * of either kind of modifications performed.
86    */

87   public static final String JavaDoc STAT_TRACKER_MOD_OVERALL_COUNT =
88        "Overall Modifications Performed";
89
90
91
92   /**
93    * The display name for the stat tracker that will be used to track the number
94    * of exceptions caught.
95    */

96   public static final String JavaDoc STAT_TRACKER_EXCEPTIONS_CAUGHT =
97        "Exceptions Caught";
98
99
100
101   /**
102    * The display name of the stat tracker that will be used to categorize the
103    * types of modifications performed.
104    */

105   public static final String JavaDoc STAT_TRACKER_MOD_CATEGORIES =
106        "Modifications by Category";
107
108
109
110   /**
111    * The display name for the stat tracker that will be used to track the
112    * replicaion latency.
113    */

114   public static final String JavaDoc STAT_TRACKER_REPLICA_LATENCY =
115        "Replication Latency (ms)";
116
117
118
119   /**
120    * The display name for the stat tracker that will be used to categorize the
121    * replication latencies.
122    */

123   public static final String JavaDoc STAT_TRACKER_CATEGORIZED_LATENCY =
124        "Categorized Latency";
125
126
127
128   /**
129    * The characters that are available for use in the randomly-generated values.
130    */

131   public static final char[] ALPHABET =
132        "abcdefghijklmnopqrstuvwxyz".toCharArray();
133
134
135
136
137
138   // The parameter that indicates whether to disconnect after each search
139
BooleanParameter disconnectParameter =
140        new BooleanParameter("disconnect", "Always Disconnect",
141                             "Indicates whether to close the connection after " +
142                             "each modification", false);
143
144   // The parmeter that specifies the cool-down time in seconds.
145
IntegerParameter coolDownParameter =
146        new IntegerParameter("cool_down", "Cool Down Time",
147                             "The time in seconds that the job should " +
148                             "continue searching after ending statistics " +
149                             "collection.", true, 0, true, 0, false, 0);
150
151   // The parameter that indicates the delay that should be used between each
152
// request sent by a thread.
153
IntegerParameter delayParameter =
154        new IntegerParameter("delay", "Time Between Requests (ms)",
155                             "Specifies the length of time in milliseconds " +
156                             "each thread should wait between modify " +
157                             "requests. Note that this delay will be " +
158                             "between consecutive requests and not between " +
159                             "the response of one operation and the request " +
160                             "for the next. If a modify takes longer than " +
161                             "this length of time, then there will be no delay.",
162                             true, 0, true, 0, false, 0);
163
164   // The parameter that indicates the number of times the search should be
165
// performed
166
IntegerParameter iterationsParameter =
167     new IntegerParameter("iterations", "Number of Iterations",
168                          "The number of searches that should be performed by " +
169                          "each thread", false, -1);
170
171   // The parameter that indicates the number of characters that should be
172
// included in the replacement value used in the modify.
173
IntegerParameter lengthParameter =
174        new IntegerParameter("length", "Value Length",
175                             "The length that should be used for the new " +
176                             "value of the modified attribute.", true, 80,
177                             true, 1, false, 0);
178
179   // The parameter that indicates the minimum length of time to sleep between
180
// modifications of the latency check entry.
181
IntegerParameter replicaDelayParameter =
182        new IntegerParameter("latency_delay", "Time Between Latency Checks (ms)",
183                             "Specifies the minimum length of time in " +
184                             "milliseconds that should pass between latency " +
185                             "checks. If a replicated operation takes longer " +
186                             "than this length of time, then there will be no " +
187                             "delay.", true, 0, true, 0, false, 0);
188
189   // The parameter that indicates the port number for the master directory.
190
IntegerParameter masterPortParameter =
191        new IntegerParameter("master_port", "Master Directory Port",
192                             "The port number for the master directory server",
193                             true, 389, true, 1, true, 65535);
194
195   // The parameter that indicates the port number for the replica directory.
196
IntegerParameter replicaPortParameter =
197        new IntegerParameter("replica_port", "Replica Directory Port",
198                             "The port number for the replica directory server",
199                             true, 389, true, 1, true, 65535);
200
201   // The parameter that indicates the maximum time limit for modify operations.
202
IntegerParameter timeLimitParameter =
203        new IntegerParameter("time_limit", "Modify Time Limit",
204                             "The maximum length of time in seconds that the " +
205                             "thread should wait for a modify operation to be " +
206                             "performed before cancelling it and trying " +
207                             "another.", false, 0, true, 0, false, 0);
208
209   // The parmeter that specifies the cool-down time in seconds.
210
IntegerParameter warmUpParameter =
211        new IntegerParameter("warm_up", "Warm Up Time",
212                             "The time in seconds that the job should " +
213                             "search before beginning statistics collection.",
214                             true, 0, true, 0, false, 0);
215
216   // The parameter that specifies the percentage of the time that the first DN
217
// will be used in the modification.
218
IntegerParameter weightParameter =
219        new IntegerParameter("weight", "DN 1 Percentage",
220                             "The percentage of the time that a DN should be " +
221                             "selected according to the value provided for " +
222                             "the Entry DN 1 parameter.", true, 50, true, 0,
223                             true, 100);
224
225   // The parameter that specifies the attribute to modify
226
MultiLineTextParameter attributeParameter =
227        new MultiLineTextParameter("attribute", "Attribute(s) to Modify",
228                                   "The set of attribute to modify in the " +
229                                   "entry. If multiple attributes are to be " +
230                                   "modified, then a separate attribute " +
231                                   "should be listed per line. Each will be " +
232                                   "given the same value.",
233                                   new String JavaDoc[] { "description" }, true);
234
235   // The placeholder parameter used as a spacer in the admin interface.
236
PlaceholderParameter placeholder = new PlaceholderParameter();
237
238   // The parameter that indicates the DN to use when binding to the server
239
StringParameter bindDNParameter =
240        new StringParameter("binddn", "Bind DN",
241                            "The DN to use to bind to the server", false, "");
242
243   // The parameter that indicates the DN or DN range to use for the first set.
244
StringParameter entryDN1Parameter =
245        new StringParameter("entrydn1", "Entry DN 1",
246                            "The DN or DN range of the first entry to modify",
247                            true, "");
248
249   // The parameter that indicates the DN or DN range to use for the second set.
250
StringParameter entryDN2Parameter =
251        new StringParameter("entrydn2", "Entry DN 2",
252                            "The DN or DN range of the second entry to modify",
253                            true, "");
254
255   // The parameter that indicates the address of the master directory server
256
StringParameter masterHostParameter =
257        new StringParameter("masterhost", "Master Directory Host",
258                            "The DNS hostname or IP address of the master " +
259                            "directory server", true, "");
260
261   // The parameter that indicates the address of the replica directory server
262
StringParameter replicaHostParameter =
263        new StringParameter("replicahost", "Replica Directory Host",
264                            "The DNS hostname or IP address of the replica " +
265                            "directory server", true, "");
266
267   // The parameter that indicates the DN to use to proxy the modifications.
268
StringParameter proxyAsDNParameter =
269        new StringParameter("proxy_as_dn", "Proxy As DN",
270                            "The DN of the user whose credentials should be " +
271                            "used to perform the modification through the use " +
272                            "of the proxied authorization control.", false, "");
273
274   // The parameter that specifies the DN of the entry to watch for replication
275
// latency.
276
StringParameter replicaEntryDNParameter =
277        new StringParameter("replica_entrydn", "Latency Check Entry DN",
278                            "The DN of the entry that should be periodically " +
279                            "modified to measure the latency of replication. " +
280                            "Note that this DN must not be the same as " +
281                            "the DN of any of the entries to modify, nor " +
282                            "should this entry be modified by any external " +
283                            "process during the test.", true, "");
284
285   // The parameter that indicates the bind password
286
PasswordParameter bindPWParameter =
287        new PasswordParameter("bindpw", "Bind Password",
288                              "The password for the bind DN", false, "");
289
290
291   // Instance variables that correspond to the parameter values
292
static boolean alwaysDisconnect;
293   static boolean useDN1Range;
294   static boolean useDN2Range;
295   static boolean useProxyAuth;
296   static boolean useDN1Sequential;
297   static boolean useDN2Sequential;
298   static int coolDownTime;
299   static int dn1RangeMax;
300   static int dn1RangeMin;
301   static int dn1RangeSpan;
302   static int dn1Weight;
303   static int dn2RangeMax;
304   static int dn2RangeMin;
305   static int dn2RangeSpan;
306   static int iterations;
307   static int latencyDelay;
308   static int length;
309   static int masterPort;
310   static int replicaPort;
311   static int sequentialCounter1;
312   static int sequentialCounter2;
313   static int timeLimit;
314   static int warmUpTime;
315   static long delay;
316   static String JavaDoc bindDN;
317   static String JavaDoc bindPassword;
318   static String JavaDoc dn1Initial;
319   static String JavaDoc dn1Final;
320   static String JavaDoc dn2Initial;
321   static String JavaDoc dn2Final;
322   static String JavaDoc masterHost;
323   static String JavaDoc proxyAsDN;
324   static String JavaDoc replicaEntryDN;
325   static String JavaDoc replicaHost;
326   static String JavaDoc[] modifyAttrs;
327
328
329   // The connection to the directory server to use to perform the modifies.
330
LDAPConnection conn;
331
332
333   // Variables used for status counters
334
CategoricalTracker modCategories;
335   IncrementalTracker exceptionsCaught;
336   IncrementalTracker mod1Count;
337   IncrementalTracker mod2Count;
338   IncrementalTracker modOverallCount;
339   TimeTracker mod1Time;
340   TimeTracker mod2Time;
341   TimeTracker modOverallTime;
342
343
344   // One random number generator for use throughout the client and another to
345
// use for only the current thread.
346
static Random parentRandom;
347   Random random;
348
349
350   // Variables used for tracking replication latency.
351
static boolean latencyTrackerChosen;
352   boolean reportLatencyTracker;
353   LatencyCheckMasterThread masterThread;
354   LatencyCheckReplicaThread replicaThread;
355
356
357
358   /**
359    * The default constructor used to create a new instance of the search thread.
360    * The only thing it should do is to invoke the superclass constructor. All
361    * other initialization should be performed in the <CODE>initialize</CODE>
362    * method.
363    */

364   public WeightedModRateWithReplicaLatencyJobClass()
365   {
366     super();
367   }
368
369
370
371   /**
372    * Retrieves the name of the job performed by this job thread.
373    *
374    * @return The name of the job performed by this job thread.
375    */

376   public String JavaDoc getJobName()
377   {
378     return "LDAP Weighted ModRate with Replica Latency";
379   }
380
381
382
383   /**
384    * Retrieves a description of the job performed by this job thread.
385    *
386    * @return A description of the job performed by this job thread.
387    */

388   public String JavaDoc getJobDescription()
389   {
390     return "This job can be used to perform repeated modifications against " +
391            "an LDAP directory server to generate load and measure " +
392            "performance. It also provides the capability to measure the " +
393            "latency associated with replication while the modifications are " +
394            "in progress.";
395   }
396
397
398
399   /**
400    * Retrieves the name of the category in which this job class exists. This is
401    * used to help arrange the job classes in the administrative interface.
402    *
403    * @return The name of the category in which this job class exists.
404    */

405   public String JavaDoc getJobCategoryName()
406   {
407     return "LDAP";
408   }
409
410
411
412   /**
413    * Retrieve a parameter list that can be used to determine all of the
414    * customizeable options that are available for this job.
415    *
416    * @return A parameter list that can be used to determine all of the
417    * customizeable options that are available for this job.
418    */

419   public ParameterList getParameterStubs()
420   {
421     Parameter[] parameters = new Parameter[]
422     {
423       placeholder,
424       masterHostParameter,
425       masterPortParameter,
426       bindDNParameter,
427       bindPWParameter,
428       proxyAsDNParameter,
429       placeholder,
430       entryDN1Parameter,
431       entryDN2Parameter,
432       weightParameter,
433       placeholder,
434       attributeParameter,
435       lengthParameter,
436       placeholder,
437       replicaHostParameter,
438       replicaPortParameter,
439       replicaEntryDNParameter,
440       replicaDelayParameter,
441       placeholder,
442       warmUpParameter,
443       coolDownParameter,
444       timeLimitParameter,
445       delayParameter,
446       placeholder,
447       iterationsParameter,
448       disconnectParameter
449     };
450
451     return new ParameterList(parameters);
452   }
453
454
455
456   /**
457    * Retrieves the set of stat trackers that will be maintained by this job
458    * class. The stat trackers returned by this method do not have to actually
459    * contain any statistics -- the display name and stat tracker class should
460    * be the only information that callers of this method should rely upon. Note
461    * that this list can be different from the list of statistics actually
462    * collected by the job in some cases (e.g., if the job may not return all the
463    * stat trackers it advertises in all cases, or if the job may return stat
464    * trackers that it did not advertise), but it is a possibility that only the
465    * stat trackers returned by this method will be accessible for some features
466    * in the SLAMD server.
467    *
468    * @param clientID The client ID that should be used for the
469    * returned stat trackers.
470    * @param threadID The thread ID that should be used for the
471    * returned stat trackers.
472    * @param collectionInterval The collection interval that should be used for
473    * the returned stat trackers.
474    *
475    * @return The set of stat trackers that will be maintained by this job
476    * class.
477    */

478   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
479                                            int collectionInterval)
480   {
481     return new StatTracker[]
482     {
483       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MOD_OVERALL_COUNT,
484                              collectionInterval),
485       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MOD_1_COUNT,
486                              collectionInterval),
487       new IncrementalTracker(clientID, threadID, STAT_TRACKER_MOD_2_COUNT,
488                              collectionInterval),
489       new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_OVERALL_TIME,
490                       collectionInterval),
491       new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_1_TIME,
492                       collectionInterval),
493       new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_2_TIME,
494                       collectionInterval),
495       new IncrementalTracker(clientID, threadID, STAT_TRACKER_EXCEPTIONS_CAUGHT,
496                              collectionInterval),
497       new CategoricalTracker(clientID, threadID, STAT_TRACKER_MOD_CATEGORIES,
498                              collectionInterval),
499       new TimeTracker(clientID, threadID, STAT_TRACKER_REPLICA_LATENCY,
500                       collectionInterval),
501       new CategoricalTracker(clientID, threadID,
502                              STAT_TRACKER_CATEGORIZED_LATENCY,
503                              collectionInterval)
504     };
505   }
506
507
508
509   /**
510    * Retrieves the stat trackers that are maintained for this job thread.
511    *
512    * @return The stat trackers that are maintained for this job thread.
513    */

514   public StatTracker[] getStatTrackers()
515   {
516     if (reportLatencyTracker)
517     {
518       return new StatTracker[]
519       {
520         modOverallCount,
521         mod1Count,
522         mod2Count,
523         modOverallTime,
524         mod1Time,
525         mod2Time,
526         exceptionsCaught,
527         modCategories,
528         latencyTime,
529         latencyCategories
530       };
531     }
532     else
533     {
534       return new StatTracker[]
535       {
536         modOverallCount,
537         mod1Count,
538         mod2Count,
539         modOverallTime,
540         mod1Time,
541         mod2Time,
542         exceptionsCaught,
543         modCategories
544       };
545     }
546   }
547
548
549
550   /**
551    * Indicates whether this job class implements logic that makes it possible to
552    * test the validity of job parameters before scheduling the job for execution
553    * (e.g., to see if the server is reachable using the information provided).
554    *
555    * @return <CODE>true</CODE> if this job provides a means of testing the job
556    * parameters, or <CODE>false</CODE> if not.
557    */

558   public boolean providesParameterTest()
559   {
560     return true;
561   }
562
563
564
565   /**
566    * Provides a means of testing the provided job parameters to determine
567    * whether they are valid (e.g., to see if the server is reachable) before
568    * scheduling the job for execution. This method will be executed by the
569    * SLAMD server system itself and not by any of the clients.
570    *
571    * @param parameters The job parameters to be tested.
572    * @param outputMessages The lines of output that were generated as part of
573    * the testing process. Each line of output should
574    * be added to this list as a separate string, and
575    * empty strings (but not <CODE>null</CODE> values)
576    * are allowed to provide separation between
577    * different messages. No formatting should be
578    * provided for these messages, however, since they
579    * may be displayed in either an HTML or plain text
580    * interface.
581    *
582    * @return <CODE>true</CODE> if the test completed successfully, or
583    * <CODE>false</CODE> if not. Note that even if the test did not
584    * complete successfully, the user will be presented with a warning
585    * but will still be allowed to schedule the job using the provided
586    * parameters. This is necessary because the parameters may still be
587    * valid even if the server couldn't validate them at the time the
588    * job was scheduled (e.g., if the server wasn't running or could not
589    * be reached by the SLAMD server even though it could be by the
590    * clients).
591    */

592   public boolean testJobParameters(ParameterList parameters,
593                                    ArrayList outputMessages)
594   {
595     // Get all the parameters that we might need to perform the test.
596
StringParameter masterHostParam =
597          parameters.getStringParameter(masterHostParameter.getName());
598     if ((masterHostParam == null) || (! masterHostParam.hasValue()))
599     {
600       outputMessages.add("ERROR: No master directory server address was " +
601                          "provided.");
602       return false;
603     }
604     String JavaDoc masterHost = masterHostParam.getStringValue();
605
606
607     IntegerParameter masterPortParam =
608          parameters.getIntegerParameter(masterPortParameter.getName());
609     if ((masterPortParam == null) || (! masterPortParam.hasValue()))
610     {
611       outputMessages.add("ERROR: No master directory server port was " +
612                          "provided.");
613       return false;
614     }
615     int masterPort = masterPortParam.getIntValue();
616
617
618     StringParameter replicaHostParam =
619          parameters.getStringParameter(replicaHostParameter.getName());
620     if ((replicaHostParam == null) || (! replicaHostParam.hasValue()))
621     {
622       outputMessages.add("ERROR: No replica directory server address was " +
623                          "provided.");
624       return false;
625     }
626     String JavaDoc replicaHost = replicaHostParam.getStringValue();
627
628
629     IntegerParameter replicaPortParam =
630          parameters.getIntegerParameter(replicaPortParameter.getName());
631     if ((replicaPortParam == null) || (! replicaPortParam.hasValue()))
632     {
633       outputMessages.add("ERROR: No replica directory server port was " +
634                          "provided.");
635       return false;
636     }
637     int replicaPort = replicaPortParam.getIntValue();
638
639
640     String JavaDoc bindDN = "";
641     StringParameter bindDNParam =
642          parameters.getStringParameter(bindDNParameter.getName());
643     if ((bindDNParam != null) && bindDNParam.hasValue())
644     {
645       bindDN = bindDNParam.getStringValue();
646     }
647
648
649     String JavaDoc bindPassword = "";
650     PasswordParameter bindPWParam =
651          parameters.getPasswordParameter(bindPWParameter.getName());
652     if ((bindPWParam != null) && bindPWParam.hasValue())
653     {
654       bindPassword = bindPWParam.getStringValue();
655     }
656
657
658     String JavaDoc proxyAsDN = null;
659     StringParameter proxyAsDNParam =
660          parameters.getStringParameter(proxyAsDNParameter.getName());
661     if ((proxyAsDNParam != null) && proxyAsDNParam.hasValue())
662     {
663       proxyAsDN = proxyAsDNParam.getStringValue();
664     }
665
666
667     StringParameter replicaEntryDNParam =
668          parameters.getStringParameter(replicaEntryDNParameter.getName());
669     if ((replicaEntryDNParam == null) || (! replicaEntryDNParam.hasValue()))
670     {
671       outputMessages.add("ERROR: No replica check entry DN was provided.");
672       return false;
673     }
674     String JavaDoc replicaEntryDN = replicaEntryDNParam.getStringValue();
675
676
677     // Create the LDAPConnection object that we will use to communicate with the
678
// directory server.
679
LDAPConnection conn = new LDAPConnection();
680
681
682     // Attempt to establish a connection to the master server.
683
try
684     {
685       outputMessages.add("Attempting to establish a connection to master " +
686                          masterHost + ":" + masterPort + "....");
687       conn.connect(masterHost, masterPort);
688       outputMessages.add("Connected successfully.");
689       outputMessages.add("");
690     }
691     catch (Exception JavaDoc e)
692     {
693       outputMessages.add("ERROR: Unable to connect to the master server: " +
694                          stackTraceToString(e));
695       return false;
696     }
697
698
699     // Attempt to bind to the master server using the bind DN and password.
700
try
701     {
702       outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
703                          "master server with a DN of '" + bindDN + "'....");
704       conn.bind(3, bindDN, bindPassword);
705       outputMessages.add("Bound successfully.");
706       outputMessages.add("");
707     }
708     catch (Exception JavaDoc e)
709     {
710       try
711       {
712         conn.disconnect();
713       } catch (Exception JavaDoc e2) {}
714
715       outputMessages.add("ERROR: Unable to bind to the master server: " +
716                          stackTraceToString(e));
717       return false;
718     }
719
720
721     // If a proxy user was specified, make sure that it exists.
722
if (proxyAsDN != null)
723     {
724       try
725       {
726         outputMessages.add("Checking to make sure that the proxied user '" +
727                            proxyAsDN + "' exists in the master....");
728         LDAPEntry proxyUserEntry = conn.read(proxyAsDN, new String JavaDoc[] { "1.1" });
729         if (proxyUserEntry == null)
730         {
731           try
732           {
733             conn.disconnect();
734           } catch (Exception JavaDoc e2) {}
735
736           outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
737                              "entry.");
738           return false;
739         }
740         else
741         {
742           outputMessages.add("Successfully read the proxied user's entry.");
743           outputMessages.add("");
744         }
745       }
746       catch (Exception JavaDoc e)
747       {
748         try
749         {
750           conn.disconnect();
751         } catch (Exception JavaDoc e2) {}
752
753         outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
754                            "entry: " + stackTraceToString(e));
755         return false;
756       }
757     }
758
759
760     // Make sure that the entry specified as the replica check entry exists.
761
try
762     {
763       outputMessages.add("Checking to make sure that the replica check " +
764                          "entry '" + replicaEntryDN +
765                          "' exists in the master....");
766       LDAPEntry baseDNEntry = conn.read(replicaEntryDN, new String JavaDoc[] { "1.1" });
767       if (baseDNEntry == null)
768       {
769         try
770         {
771           conn.disconnect();
772         } catch (Exception JavaDoc e2) {}
773
774         outputMessages.add("ERROR: Unable to retrieve the replica check " +
775                            "entry.");
776         return false;
777       }
778       else
779       {
780         outputMessages.add("Successfully read the replica check entry.");
781         outputMessages.add("");
782       }
783     }
784     catch (Exception JavaDoc e)
785     {
786       try
787       {
788         conn.disconnect();
789       } catch (Exception JavaDoc e2) {}
790
791       outputMessages.add("ERROR: Unable to retrieve the replica check " +
792                          "entry: " + stackTraceToString(e));
793       return false;
794     }
795
796
797     // At this point, all tests on the master have passed. Close the connection
798
// and prepare to start on the replica.
799
try
800     {
801       conn.disconnect();
802     } catch (Exception JavaDoc e) {}
803
804
805     // Attempt to establish a connection to the replica server.
806
try
807     {
808       outputMessages.add("Attempting to establish a connection to replica " +
809                          replicaHost + ":" + replicaPort + "....");
810       conn.connect(replicaHost, replicaPort);
811       outputMessages.add("Connected successfully.");
812       outputMessages.add("");
813     }
814     catch (Exception JavaDoc e)
815     {
816       outputMessages.add("ERROR: Unable to connect to the replica server: " +
817                          stackTraceToString(e));
818       return false;
819     }
820
821
822     // Attempt to bind to the replica server using the bind DN and password.
823
try
824     {
825       outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
826                          "replica server with a DN of '" + bindDN + "'....");
827       conn.bind(3, bindDN, bindPassword);
828       outputMessages.add("Bound successfully.");
829       outputMessages.add("");
830     }
831     catch (Exception JavaDoc e)
832     {
833       try
834       {
835         conn.disconnect();
836       } catch (Exception JavaDoc e2) {}
837
838       outputMessages.add("ERROR: Unable to bind to the replica server: " +
839                          stackTraceToString(e));
840       return false;
841     }
842
843
844     // Make sure that the entry specified as the replica check entry exists.
845
try
846     {
847       outputMessages.add("Checking to make sure that the replica check " +
848                          "entry '" + replicaEntryDN +
849                          "' exists in the replica....");
850       LDAPEntry baseDNEntry = conn.read(replicaEntryDN, new String JavaDoc[] { "1.1" });
851       if (baseDNEntry == null)
852       {
853         try
854         {
855           conn.disconnect();
856         } catch (Exception JavaDoc e2) {}
857
858         outputMessages.add("ERROR: Unable to retrieve the replica check " +
859                            "entry.");
860         return false;
861       }
862       else
863       {
864         outputMessages.add("Successfully read the replica check entry.");
865         outputMessages.add("");
866       }
867     }
868     catch (Exception JavaDoc e)
869     {
870       try
871       {
872         conn.disconnect();
873       } catch (Exception JavaDoc e2) {}
874
875       outputMessages.add("ERROR: Unable to retrieve the replica check " +
876                          "entry: " + stackTraceToString(e));
877       return false;
878     }
879
880
881     // At this point, all tests on the replica have passed. Close the
882
// connection and return true.
883
try
884     {
885       conn.disconnect();
886     } catch (Exception JavaDoc e) {}
887
888
889     outputMessages.add("All tests completed successfully.");
890     return true;
891   }
892
893
894
895   /**
896    * Initializes all of the instance variables that correspond to job
897    * parameters.
898    *
899    * @param clientID The client ID for the current client.
900    * @param parameters The set of parameters that have been defined for this
901    * job.
902    *
903    * @throws UnableToRunException If any part of the initialization fails.
904    */

905   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
906          throws UnableToRunException
907   {
908     // Initialize the latency check mutex and indicate that no latency tracking
909
// thread has yet been chosen.
910
latencyTrackerChosen = false;
911
912     // Get the address of the master directory server
913
masterHost = null;
914     masterHostParameter =
915          parameters.getStringParameter(masterHostParameter.getName());
916     if (masterHostParameter != null)
917     {
918       masterHost = masterHostParameter.getStringValue();
919     }
920
921     // Get the port for the master directory server
922
masterPort = 389;
923     masterPortParameter =
924          parameters.getIntegerParameter(masterPortParameter.getName());
925     if (masterPortParameter != null)
926     {
927       masterPort = masterPortParameter.getIntValue();
928     }
929
930     // Get the address of the replica directory server
931
replicaHost = null;
932     replicaHostParameter =
933          parameters.getStringParameter(replicaHostParameter.getName());
934     if (replicaHostParameter != null)
935     {
936       replicaHost = replicaHostParameter.getStringValue();
937     }
938
939     // Get the port for the replica directory server
940
replicaPort = 389;
941     replicaPortParameter =
942          parameters.getIntegerParameter(replicaPortParameter.getName());
943     if (replicaPortParameter != null)
944     {
945       replicaPort = replicaPortParameter.getIntValue();
946     }
947
948     // Get the bind DN for the target directory server
949
bindDN = "";
950     bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
951     if (bindDNParameter != null)
952     {
953       bindDN = bindDNParameter.getStringValue();
954     }
955
956     // Get the bind password for the target directory server
957
bindPassword = "";
958     bindPWParameter =
959          parameters.getPasswordParameter(bindPWParameter.getName());
960     if (bindPWParameter != null)
961     {
962       bindPassword = bindPWParameter.getStringValue();
963     }
964
965     // Get the DN of the proxy as user.
966
useProxyAuth = false;
967     proxyAsDNParameter =
968          parameters.getStringParameter(proxyAsDNParameter.getName());
969     if ((proxyAsDNParameter != null) && (proxyAsDNParameter.hasValue()))
970     {
971       useProxyAuth = true;
972       proxyAsDN = proxyAsDNParameter.getStringValue();
973     }
974
975     // Get the DN of the first entry to modify
976
entryDN1Parameter =
977          parameters.getStringParameter(entryDN1Parameter.getName());
978     if (entryDN1Parameter != null)
979     {
980       String JavaDoc entryDN = entryDN1Parameter.getStringValue();
981       useDN1Range = true;
982       useDN1Sequential = false;
983
984       try
985       {
986         int openPos = entryDN.indexOf('[');
987         int dashPos = entryDN.indexOf('-', openPos);
988         if (dashPos < 0)
989         {
990           dashPos = entryDN.indexOf(':', openPos);
991           useDN1Sequential = true;
992         }
993         int closePos = entryDN.indexOf(']', dashPos);
994
995         dn1Initial = entryDN.substring(0, openPos);
996         dn1Final = entryDN.substring(closePos+1);
997
998         dn1RangeMin = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
999         dn1RangeMax = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1000        dn1RangeSpan = dn1RangeMax - dn1RangeMin + 1;
1001        sequentialCounter1 = dn1RangeMin;
1002      }
1003      catch (Exception JavaDoc e)
1004      {
1005        useDN1Range = false;
1006        dn1Initial = entryDN;
1007      }
1008    }
1009
1010    // Get the DN of the second entry to modify
1011
entryDN2Parameter =
1012         parameters.getStringParameter(entryDN2Parameter.getName());
1013    if (entryDN2Parameter != null)
1014    {
1015      String JavaDoc entryDN = entryDN2Parameter.getStringValue();
1016      useDN2Range = true;
1017      useDN2Sequential = false;
1018
1019      try
1020      {
1021        int openPos = entryDN.indexOf('[');
1022        int dashPos = entryDN.indexOf('-', openPos);
1023        if (dashPos < 0)
1024        {
1025          dashPos = entryDN.indexOf(':', openPos);
1026          useDN2Sequential = true;
1027        }
1028        int closePos = entryDN.indexOf(']', dashPos);
1029
1030        dn2Initial = entryDN.substring(0, openPos);
1031        dn2Final = entryDN.substring(closePos+1);
1032
1033        dn2RangeMin = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
1034        dn2RangeMax = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
1035        dn2RangeSpan = dn2RangeMax - dn2RangeMin + 1;
1036        sequentialCounter2 = dn2RangeMin;
1037      }
1038      catch (Exception JavaDoc e)
1039      {
1040        useDN2Range = false;
1041        dn2Initial = entryDN;
1042      }
1043    }
1044
1045    // Get the weight to use when choosing between DN 1 and DN 2.
1046
dn1Weight = 50;
1047    weightParameter = parameters.getIntegerParameter(weightParameter.getName());
1048    if (weightParameter != null)
1049    {
1050      dn1Weight = weightParameter.getIntValue();
1051    }
1052
1053    // Get the DN of the entry to use in the latency checks.
1054
replicaEntryDN = null;
1055    replicaEntryDNParameter =
1056         parameters.getStringParameter(replicaEntryDNParameter.getName());
1057    if (replicaEntryDNParameter != null)
1058    {
1059      replicaEntryDN = replicaEntryDNParameter.getStringValue();
1060    }
1061
1062    // Get the attribute to modify.
1063
attributeParameter =
1064         parameters.getMultiLineTextParameter(attributeParameter.getName());
1065    if (attributeParameter != null)
1066    {
1067      modifyAttrs = attributeParameter.getNonBlankLines();
1068    }
1069
1070    // Get the length to use in the modification.
1071
length = 80;
1072    lengthParameter =
1073         parameters.getIntegerParameter(lengthParameter.getName());
1074    if (lengthParameter != null)
1075    {
1076      length = lengthParameter.getIntValue();
1077    }
1078
1079    // Get the warm up time.
1080
warmUpTime = 0;
1081    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1082    if (warmUpParameter != null)
1083    {
1084      warmUpTime = warmUpParameter.getIntValue();
1085    }
1086
1087    // Get the cool down time.
1088
coolDownTime = 0;
1089    coolDownParameter =
1090         parameters.getIntegerParameter(coolDownParameter.getName());
1091    if (coolDownParameter != null)
1092    {
1093      coolDownTime = coolDownParameter.getIntValue();
1094    }
1095
1096    // Get the maximum modify time limit.
1097
timeLimit = 0;
1098    timeLimitParameter =
1099         parameters.getIntegerParameter(timeLimitParameter.getName());
1100    if (timeLimitParameter != null)
1101    {
1102      timeLimit = timeLimitParameter.getIntValue();
1103    }
1104
1105    // Get the delay between requests.
1106
delay = 0;
1107    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1108    if (delayParameter != null)
1109    {
1110      delay = delayParameter.getIntValue();
1111    }
1112
1113    // Get the delay between latency checks.
1114
latencyDelay = 0;
1115    replicaDelayParameter =
1116         parameters.getIntegerParameter(replicaDelayParameter.getName());
1117    if (replicaDelayParameter != null)
1118    {
1119      latencyDelay = replicaDelayParameter.getIntValue();
1120    }
1121
1122    // Get the number of iterations to perform
1123
iterations = -1;
1124    iterationsParameter =
1125         parameters.getIntegerParameter(iterationsParameter.getName());
1126    if (iterationsParameter != null)
1127    {
1128      iterations = iterationsParameter.getIntValue();
1129    }
1130
1131    // Get the flag indicating whether we should disconnect after each search
1132
alwaysDisconnect = false;
1133    disconnectParameter =
1134         parameters.getBooleanParameter(disconnectParameter.getName());
1135    if (disconnectParameter != null)
1136    {
1137      alwaysDisconnect = disconnectParameter.getBooleanValue();
1138    }
1139
1140
1141    // Initialize the parent random number generator
1142
parentRandom = new Random();
1143  }
1144
1145
1146
1147  /**
1148   * Initializes this job thread to be used to actually run the job on the
1149   * client. The provided parameter list should be processed to customize the
1150   * behavior of this job thread, and any other initialization that needs to be
1151   * done in order for the job to run should be performed here as well.
1152   *
1153   * @param clientID The client ID for this job thread.
1154   * @param threadID The thread ID for this job thread.
1155   * @param collectionInterval The length of time in seconds to use as the
1156   * statistics collection interval.
1157   * @param parameters The set of parameters provided to this job that
1158   * can be used to customize its behavior.
1159   *
1160   * @throws UnableToRunException If a problem occurs that prevents the thread
1161   * from being able to run properly.
1162   */

1163  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1164                               int collectionInterval, ParameterList parameters)
1165         throws UnableToRunException
1166  {
1167    // Set up the stat trackers
1168
modOverallCount = new IncrementalTracker(clientID, threadID,
1169                                             STAT_TRACKER_MOD_OVERALL_COUNT,
1170                                             collectionInterval);
1171    mod1Count = new IncrementalTracker(clientID, threadID,
1172                                       STAT_TRACKER_MOD_1_COUNT,
1173                                       collectionInterval);
1174    mod2Count = new IncrementalTracker(clientID, threadID,
1175                                       STAT_TRACKER_MOD_2_COUNT,
1176                                       collectionInterval);
1177    modOverallTime = new TimeTracker(clientID, threadID,
1178                                     STAT_TRACKER_MOD_OVERALL_TIME,
1179                                     collectionInterval);
1180    mod1Time = new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_1_TIME,
1181                               collectionInterval);
1182    mod2Time = new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_2_TIME,
1183                               collectionInterval);
1184    exceptionsCaught = new IncrementalTracker(clientID, threadID,
1185                                              STAT_TRACKER_EXCEPTIONS_CAUGHT,
1186                                              collectionInterval);
1187    modCategories = new CategoricalTracker(clientID, threadID,
1188                                           STAT_TRACKER_MOD_CATEGORIES,
1189                                           collectionInterval);
1190
1191
1192    // Enable real-time reporting of the data for these stat trackers.
1193
RealTimeStatReporter statReporter = getStatReporter();
1194    if (statReporter != null)
1195    {
1196      String JavaDoc jobID = getJobID();
1197      modOverallCount.enableRealTimeStats(statReporter, jobID);
1198      mod1Count.enableRealTimeStats(statReporter, jobID);
1199      mod2Count.enableRealTimeStats(statReporter, jobID);
1200      modOverallTime.enableRealTimeStats(statReporter, jobID);
1201      mod1Time.enableRealTimeStats(statReporter, jobID);
1202      mod2Time.enableRealTimeStats(statReporter, jobID);
1203      exceptionsCaught.enableRealTimeStats(statReporter, jobID);
1204    }
1205
1206
1207    // Initialize the random number generator for this thread.
1208
random = new Random(parentRandom.nextLong());
1209
1210    // See if this thread should be used to report the replica latency
1211
// information. If so, then start the latency check threads.
1212
if ((! latencyTrackerChosen) && (getClientNumber() == 0))
1213    {
1214      latencyCheckMutex = new Object JavaDoc();
1215      latencyTrackerChosen = true;
1216      reportLatencyTracker = true;
1217
1218      // Create the latency timer stat tracker.
1219
latencyTime = new TimeTracker(clientID, threadID,
1220                                    STAT_TRACKER_REPLICA_LATENCY,
1221                                    collectionInterval);
1222
1223      // Create the latency categories stat tracker.
1224
latencyCategories =
1225           new CategoricalTracker(clientID, threadID,
1226                                  STAT_TRACKER_CATEGORIZED_LATENCY,
1227                                  collectionInterval);
1228
1229      // Create the latency thread that will make changes to the master server.
1230
try
1231      {
1232        masterThread =
1233             new LatencyCheckMasterThread(this, masterHost, masterPort, bindDN,
1234                                          bindPassword, replicaEntryDN,
1235                                          modifyAttrs[0], latencyDelay);
1236      }
1237      catch (LDAPException le)
1238      {
1239        throw new UnableToRunException("Could not create the master latency " +
1240                                       "thread: " + le, le);
1241      }
1242
1243      // Create the latency thread that will read changes from the replica.
1244
try
1245      {
1246        replicaThread =
1247             new LatencyCheckReplicaThread(this, replicaHost, replicaPort,
1248                                           bindDN, bindPassword,
1249                                           replicaEntryDN);
1250      }
1251      catch (LDAPException le)
1252      {
1253        throw new UnableToRunException("Could not create the replica latency " +
1254                                       "thread: " + le, le);
1255      }
1256
1257      // Start the latency check threads.
1258
masterThread.start();
1259      replicaThread.start();
1260    }
1261    else
1262    {
1263      reportLatencyTracker = false;
1264    }
1265  }
1266
1267
1268
1269  /**
1270   * Perform the work of this job thread by establishing the connection(s) to
1271   * the directory server and issuing all the appropriate queries. The job will
1272   * continue until the specified number of iterations have been performed, the
1273   * stop time has been reached, the maximum duration has been reached, or the
1274   * SLAMD server indicates that a stop has been requested.
1275   */

1276  public void runJob()
1277  {
1278    // Determine the range of time for which we should collect statistics.
1279
long currentTime = System.currentTimeMillis();
1280    boolean collectingStats = false;
1281    long startCollectingTime = currentTime + (1000 * warmUpTime);
1282    long stopCollectingTime = Long.MAX_VALUE;
1283    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1284    {
1285      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1286    }
1287
1288    // Set a variable that we can use to determine if the connection is alive or
1289
// not
1290
boolean connected = false;
1291
1292    // Set a variable that can be used to determine how long we should sleep
1293
// between modifications.
1294
long modStartTime = 0;
1295
1296    // First, see if this should operate "infinitely" (i.e., not a fixed number
1297
// of iterations
1298
boolean infinite = (iterations <= 0);
1299
1300    // Create a variable that we will use for the LDAP connection
1301
conn = new LDAPConnection();
1302
1303
1304    // Create a loop that will run until it needs to stop
1305
for (int i=0; ((! shouldStop()) && ((infinite || (i < iterations)))); i++)
1306    {
1307      currentTime = System.currentTimeMillis();
1308      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1309          (currentTime < stopCollectingTime))
1310      {
1311        // Tell the stat trackers that they should start tracking now
1312
modOverallCount.startTracker();
1313        mod1Count.startTracker();
1314        mod2Count.startTracker();
1315        modOverallTime.startTracker();
1316        mod1Time.startTracker();
1317        mod2Time.startTracker();
1318        exceptionsCaught.startTracker();
1319        modCategories.startTracker();
1320
1321        if (reportLatencyTracker)
1322        {
1323          latencyTime.startTracker();
1324          latencyCategories.startTracker();
1325          replicaThread.startChecking();
1326          masterThread.startChecking();
1327        }
1328
1329        collectingStats = true;
1330      }
1331      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1332      {
1333        modOverallCount.stopTracker();
1334        mod1Count.stopTracker();
1335        mod2Count.stopTracker();
1336        modOverallTime.stopTracker();
1337        mod1Time.stopTracker();
1338        mod2Time.stopTracker();
1339        exceptionsCaught.stopTracker();
1340        modCategories.stopTracker();
1341
1342        if (reportLatencyTracker)
1343        {
1344          latencyTime.stopTracker();
1345          latencyCategories.stopTracker();
1346          replicaThread.stopAndWait();
1347          masterThread.stopAndWait();
1348        }
1349
1350        collectingStats = false;
1351      }
1352
1353      // If the connection is currently not connected, then establish it
1354
if (! connected)
1355      {
1356        try
1357        {
1358          conn.connect(3, masterHost, masterPort, bindDN, bindPassword);
1359          connected = true;
1360        }
1361        catch (LDAPException le)
1362        {
1363          logMessage("ERROR -- Could not connect to " + masterHost + ":" +
1364                           masterPort + " (" + le + ") -- aborting thread");
1365          if (collectingStats)
1366          {
1367            exceptionsCaught.increment();
1368          }
1369          indicateStoppedDueToError();
1370          break;
1371        }
1372      }
1373
1374      LDAPConstraints constraints = conn.getConstraints();
1375      if (useProxyAuth)
1376      {
1377        LDAPProxiedAuthControl proxyAuthControl =
1378             new LDAPProxiedAuthControl(proxyAsDN, true);
1379        constraints.setServerControls(proxyAuthControl);
1380        constraints.setTimeLimit(1000 * timeLimit);
1381      }
1382
1383
1384      // Create a flag used to determine if the modification was successful.
1385
boolean successfulMod = false;
1386
1387
1388      // Determine which modification we need to perform.
1389
int randVal = (random.nextInt() & 0x7FFFFFFF) % 100;
1390      if (randVal < dn1Weight)
1391      {
1392        // Record the current time as the start of the modify
1393
if (collectingStats)
1394        {
1395          modOverallTime.startTimer();
1396          mod1Time.startTimer();
1397        }
1398        if (delay > 0)
1399        {
1400          modStartTime = System.currentTimeMillis();
1401        }
1402
1403
1404        // Perform the modification.
1405
try
1406        {
1407          String JavaDoc attrValue = getRandomString(length);
1408          LDAPModification[] mods = new LDAPModification[modifyAttrs.length];
1409          for (int j=0; j < modifyAttrs.length; j++)
1410          {
1411            LDAPAttribute attr = new LDAPAttribute(modifyAttrs[j], attrValue);
1412            mods[j] = new LDAPModification(LDAPModification.REPLACE, attr);
1413          }
1414          conn.modify(getRandomDN1(), mods, constraints);
1415          successfulMod = true;
1416        }
1417        catch (LDAPException le)
1418        {
1419          writeVerbose("ERROR while performing modification -- " + le);
1420          if (collectingStats)
1421          {
1422            exceptionsCaught.increment();
1423          }
1424          indicateCompletedWithErrors();
1425        }
1426
1427
1428        // Record the current time as the end of the modification
1429
if (collectingStats)
1430        {
1431          modOverallTime.stopTimer();
1432          mod1Time.stopTimer();
1433        }
1434
1435
1436        // Update the appropriate status counters
1437
if (successfulMod && collectingStats)
1438        {
1439          modOverallCount.increment();
1440          mod1Count.increment();
1441          modCategories.increment("DN 1");
1442        }
1443      }
1444      else
1445      {
1446        // Record the current time as the start of the modify
1447
if (collectingStats)
1448        {
1449          modOverallTime.startTimer();
1450          mod2Time.startTimer();
1451        }
1452        if (delay > 0)
1453        {
1454          modStartTime = System.currentTimeMillis();
1455        }
1456
1457
1458        // Perform the modification.
1459
try
1460        {
1461          String JavaDoc attrValue = getRandomString(length);
1462          LDAPModification[] mods = new LDAPModification[modifyAttrs.length];
1463          for (int j=0; j < modifyAttrs.length; j++)
1464          {
1465            LDAPAttribute attr = new LDAPAttribute(modifyAttrs[j], attrValue);
1466            mods[j] = new LDAPModification(LDAPModification.REPLACE, attr);
1467          }
1468          conn.modify(getRandomDN2(), mods, constraints);
1469          successfulMod = true;
1470        }
1471        catch (LDAPException le)
1472        {
1473          writeVerbose("ERROR while performing modification -- " + le);
1474          if (collectingStats)
1475          {
1476            exceptionsCaught.increment();
1477          }
1478          indicateCompletedWithErrors();
1479        }
1480
1481
1482        // Record the current time as the end of the modification
1483
if (collectingStats)
1484        {
1485          modOverallTime.stopTimer();
1486          mod2Time.stopTimer();
1487        }
1488
1489
1490        // Update the appropriate status counters
1491
if (successfulMod && collectingStats)
1492        {
1493          modOverallCount.increment();
1494          mod2Count.increment();
1495          modCategories.increment("DN 2");
1496        }
1497      }
1498
1499      // If the connection should be broken, then do so
1500
if (alwaysDisconnect)
1501      {
1502        try
1503        {
1504          conn.disconnect();
1505        } catch (LDAPException le) {}
1506        connected = false;
1507      }
1508
1509      // If we need to sleep, then do so
1510
if ((delay > 0) && (! shouldStop()))
1511      {
1512        long now = System.currentTimeMillis();
1513        long sleepTime = delay - (now - modStartTime);
1514        if (sleepTime > 0)
1515        {
1516          try
1517          {
1518            Thread.sleep(sleepTime);
1519          } catch (InterruptedException JavaDoc ie) {}
1520        }
1521      }
1522    }
1523
1524
1525    // If the connection is still established, then close it
1526
try
1527    {
1528      conn.disconnect();
1529    } catch (LDAPException le) {}
1530
1531
1532    // Tell the stat trackers that they should stop tracking
1533
if (collectingStats)
1534    {
1535      modOverallCount.stopTracker();
1536      mod1Count.stopTracker();
1537      mod2Count.stopTracker();
1538      modOverallTime.stopTracker();
1539      mod1Time.stopTracker();
1540      mod2Time.stopTracker();
1541      exceptionsCaught.stopTracker();
1542      modCategories.stopTracker();
1543
1544      if (reportLatencyTracker)
1545      {
1546        latencyTime.stopTracker();
1547        latencyCategories.stopTracker();
1548        replicaThread.stopAndWait();
1549        masterThread.stopAndWait();
1550      }
1551    }
1552  }
1553
1554
1555
1556  /**
1557   * Attempts to force this thread to exit by closing the connection to the
1558   * directory server and setting it to <CODE>null</CODE>.
1559   */

1560  public void destroy()
1561  {
1562    if (conn != null)
1563    {
1564      try
1565      {
1566        conn.disconnect();
1567      } catch (Exception JavaDoc e) {}
1568
1569      conn = null;
1570    }
1571
1572    if (masterThread != null)
1573    {
1574      masterThread.masterThread.interrupt();
1575
1576      try
1577      {
1578        masterThread.connection.disconnect();
1579      } catch (Exception JavaDoc e) {}
1580
1581      masterThread.connection = null;
1582      masterThread = null;
1583    }
1584
1585    if (replicaThread != null)
1586    {
1587      replicaThread.replicaThread.interrupt();
1588
1589      try
1590      {
1591        replicaThread.connection.disconnect();
1592      } catch (Exception JavaDoc e) {}
1593
1594      replicaThread.connection = null;
1595      replicaThread = null;
1596    }
1597  }
1598
1599
1600
1601  /**
1602   * Ensures that the master and replica check threads are properly stopped.
1603   */

1604  public void finalizeClient()
1605  {
1606    masterThread.stopAndWait();
1607    replicaThread.stopAndWait();
1608  }
1609
1610
1611
1612  /**
1613   * Retrieves a random DN from the list of DNs that can be modified.
1614   *
1615   * @return A randomly-chosen DN of an entry to modify.
1616   */

1617  public String JavaDoc getRandomDN1()
1618  {
1619    if (useDN1Range)
1620    {
1621      int value;
1622      if (useDN1Sequential)
1623      {
1624        value = sequentialCounter1++;
1625        if (sequentialCounter1 > dn1RangeMax)
1626        {
1627          sequentialCounter1 = dn1RangeMin;
1628        }
1629      }
1630      else
1631      {
1632        value = ((random.nextInt() & 0x7FFFFFFF) % dn1RangeSpan) +
1633                dn1RangeMin;
1634      }
1635      return dn1Initial + value + dn1Final;
1636    }
1637    else
1638    {
1639      return dn1Initial;
1640    }
1641  }
1642
1643
1644
1645  /**
1646   * Retrieves a random DN from the list of DNs that can be modified.
1647   *
1648   * @return A randomly-chosen DN of an entry to modify.
1649   */

1650  public String JavaDoc getRandomDN2()
1651  {
1652    if (useDN2Range)
1653    {
1654      int value;
1655      if (useDN2Sequential)
1656      {
1657        value = sequentialCounter2++;
1658        if (sequentialCounter2 > dn1RangeMax)
1659        {
1660          sequentialCounter2 = dn1RangeMin;
1661        }
1662      }
1663      else
1664      {
1665        value = ((random.nextInt() & 0x7FFFFFFF) % dn2RangeSpan) +
1666                dn2RangeMin;
1667      }
1668      return dn2Initial + value + dn2Final;
1669    }
1670    else
1671    {
1672      return dn2Initial;
1673    }
1674  }
1675
1676
1677
1678  /**
1679   * Retrieves a string containing the specified number of randomly-chosen
1680   * characters.
1681   *
1682   * @param length The number of characters to include in the string.
1683   *
1684   * @return A string containing the specified number of randomly-chosen
1685   * characters.
1686   */

1687  public String JavaDoc getRandomString(int length)
1688  {
1689    char[] returnChars = new char[length];
1690
1691    for (int i=0; i < length; i++)
1692    {
1693      returnChars[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
1694                                ALPHABET.length];
1695    }
1696
1697    return new String JavaDoc(returnChars);
1698  }
1699}
1700
1701
Popular Tags