KickJava   Java API By Example, From Geeks To Geeks.

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


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

37 public class DelRateWithReplicaLatencyJobClass
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 each delete.
43    */

44   public static final String JavaDoc STAT_TRACKER_DELETE_TIME = "Delete Time (ms)";
45
46
47
48   /**
49    * The display name for the stat tracker that will be used to track the number
50    * of deletes performed.
51    */

52   public static final String JavaDoc STAT_TRACKER_DELETE_COUNT = "Deletes Performed";
53
54
55
56   /**
57    * The display name for the stat tracker that will be used to track the number
58    * of exceptions caught.
59    */

60   public static final String JavaDoc STAT_TRACKER_RESULT_CODES = "Result Codes";
61
62
63
64   /**
65    * The display name for the stat tracker that will be used to track the
66    * replication latency.
67    */

68   public static final String JavaDoc STAT_TRACKER_REPLICA_LATENCY =
69        "Replication Latency (ms)";
70
71
72
73   /**
74    * The display name for the stat tracker that will be used to categorize the
75    * replication latencies.
76    */

77   public static final String JavaDoc STAT_TRACKER_CATEGORIZED_LATENCY =
78        "Categorized Latency";
79
80
81
82   /**
83    * The characters that are available for use in the randomly-generated values.
84    */

85   public static final char[] ALPHABET =
86        "abcdefghijklmnopqrstuvwxyz".toCharArray();
87
88
89
90   // The parameter that indicates whether to disconnect after each delete
91
BooleanParameter disconnectParameter =
92        new BooleanParameter("disconnect", "Always Disconnect",
93                             "Indicates whether to close the connection after " +
94                             "each delete.", false);
95
96   // The parameter that specifies the file containing the DNs to delete.
97
FileURLParameter dnFileParameter =
98        new FileURLParameter("dn_file", "DN File URL",
99                             "The URL (FILE or HTTP) to the file containing " +
100                             "DNs of the entries to be deleted.", null, false);
101
102   // The parmeter that specifies the cool-down time in seconds.
103
IntegerParameter coolDownParameter =
104        new IntegerParameter("cool_down", "Cool Down Time",
105                             "The time in seconds that the job should " +
106                             "continue deleting after ending statistics " +
107                             "collection.", true, 0, true, 0, false, 0);
108
109   // The parameter that indicates the delay that should be used between each
110
// request sent by a thread.
111
IntegerParameter delayParameter =
112        new IntegerParameter("delay", "Time Between Requests (ms)",
113                             "Specifies the length of time in milliseconds " +
114                             "each thread should wait between delete " +
115                             "requests. Note that this delay will be " +
116                             "between consecutive requests and not between " +
117                             "the response of one operation and the request " +
118                             "for the next. If an delete takes longer than " +
119                             "this length of time, then there will be no delay.",
120                             true, 0, true, 0, false, 0);
121
122   // The parameter that indicates the minimum length of time to sleep between
123
// modifications of the latency check entry.
124
IntegerParameter replicaDelayParameter =
125        new IntegerParameter("latency_delay", "Time Between Latency Checks (ms)",
126                             "Specifies the minimum length of time in " +
127                             "milliseconds that should pass between latency " +
128                             "checks. If a replicated operation takes longer " +
129                             "than this length of time, then there will be no " +
130                             "delay.", true, 0, true, 0, false, 0);
131
132   // The parameter that indicates the port number for the master directory
133
IntegerParameter masterPortParameter =
134        new IntegerParameter("masterport", "Master Directory Port",
135                             "The port number for the master directory server",
136                             true, 389, true, 1, true, 65535);
137
138   // The parameter that indicates the port number for the replica directory
139
IntegerParameter replicaPortParameter =
140        new IntegerParameter("replicaport", "Replica Directory Port",
141                             "The port number for the replica directory server",
142                             true, 389, true, 1, true, 65535);
143
144   // The parameter that indicates the maximum time limit for delete operations.
145
IntegerParameter timeLimitParameter =
146        new IntegerParameter("time_limit", "Delete Time Limit",
147                             "The maximum length of time in seconds that the " +
148                             "thread should wait for a delete operation to be " +
149                             "performed before cancelling it and trying " +
150                             "another.", false, 0, true, 0, false, 0);
151
152   // The parmeter that specifies the cool-down time in seconds.
153
IntegerParameter warmUpParameter =
154        new IntegerParameter("warm_up", "Warm Up Time",
155                             "The time in seconds that the job should " +
156                             "delete before beginning statistics collection.",
157                             true, 0, true, 0, false, 0);
158
159   // The placeholder parameter used as a spacer in the admin interface.
160
PlaceholderParameter placeholder = new PlaceholderParameter();
161
162   // The parameter that specifies the attribute to modify
163
StringParameter attributeParameter =
164        new StringParameter("attribute", "Attribute to Modify",
165                            "The attribute to modify for the latency checks",
166                            true, "description");
167
168   // The parameter that indicates the DN to use when binding to the server
169
StringParameter bindDNParameter =
170        new StringParameter("binddn", "Bind DN",
171                            "The DN to use to bind to the server", false, "");
172
173   // The parameter that indicates the DN pattern for the entries to delete.
174
StringParameter entryDNParameter =
175        new StringParameter("entrydn", "Entry DN Pattern",
176                            "The pattern that specifies the DNs of the " +
177                            "entries to be deleted. It may contain a " +
178                            "numeric range in brackets with the minimum and " +
179                            "maximum value separated by colons.", false, "");
180
181   // The parameter that indicates the address of the master directory server
182
StringParameter masterHostParameter =
183        new StringParameter("masterhost", "Master Directory Host",
184                            "The DNS hostname or IP address of the master " +
185                            "directory server", true, "");
186
187   // The parameter that indicates the address of the replica directory server
188
StringParameter replicaHostParameter =
189        new StringParameter("replicahost", "Replica Directory Host",
190                            "The DNS hostname or IP address of the replica " +
191                            "directory server", true, "");
192
193   // The parameter that specifies the DN of the entry to watch for replication
194
// latency
195
StringParameter replicaEntryDNParameter =
196        new StringParameter("replica_entry_dn", "Latency Check Entry DN",
197                            "The DN of the entry that should be periodically " +
198                            "modified to measure the latency of replication. " +
199                            "Note that this DN must not be the same as " +
200                            "the DN of any of the entries to modify, nor " +
201                            "should this entry be modified by any external " +
202                            "process during the test.", true, "");
203
204   // The parameter that indicates the DN to use to proxy the adds.
205
StringParameter proxyAsDNParameter =
206        new StringParameter("proxy_as_dn", "Proxy As DN",
207                            "The DN of the user whose credentials should be " +
208                            "used to perform the adds through the use " +
209                            "of the proxied authorization control.", false, "");
210
211   // The parameter that indicates the bind password
212
PasswordParameter bindPWParameter =
213        new PasswordParameter("bindpw", "Bind Password",
214                              "The password for the bind DN", false, "");
215
216
217   // Instance variables that correspond to the parameter values
218
static boolean alwaysDisconnect;
219   static boolean useProxyAuth;
220   static int coolDownTime;
221   static int dnMax;
222   static int dnMin;
223   static int latencyDelay;
224   static int masterPort;
225   static int replicaPort;
226   static int nextValue;
227   static int timeLimit;
228   static int warmUpTime;
229   static long delay;
230   static String JavaDoc attribute;
231   static String JavaDoc bindDN;
232   static String JavaDoc bindPassword;
233   static String JavaDoc dnInitial;
234   static String JavaDoc dnFinal;
235   static String JavaDoc masterHost;
236   static String JavaDoc replicaHost;
237   static String JavaDoc replicaEntryDN;
238   static String JavaDoc proxyAsDN;
239   static String JavaDoc[] entryDNs;
240
241
242   // The connection to the directory server to use when performing deletes.
243
LDAPConnection conn;
244
245
246   // Variables used for status counters
247
CategoricalTracker resultCodes;
248   IncrementalTracker deleteCount;
249   TimeTracker deleteTime;
250
251
252   // Variables used for tracking replication latency.
253
static boolean latencyTrackerChosen;
254   boolean reportLatencyTracker;
255   LatencyCheckMasterThread masterThread;
256   LatencyCheckReplicaThread replicaThread;
257
258
259   // One random number generator for use throughout the client and another to
260
// use for only the current thread.
261
static Random parentRandom;
262   Random random;
263
264
265
266
267   /**
268    * The default constructor used to create a new instance of the delete thread.
269    * The only thing it should do is to invoke the superclass constructor. All
270    * other initialization should be performed in the <CODE>initialize</CODE>
271    * method.
272    */

273   public DelRateWithReplicaLatencyJobClass()
274   {
275     super();
276   }
277
278
279
280   /**
281    * Retrieves the name of the job performed by this job thread.
282    *
283    * @return The name of the job performed by this job thread.
284    */

285   public String JavaDoc getJobName()
286   {
287     return "LDAP DelRate with Replica Latency";
288   }
289
290
291
292   /**
293    * Retrieves a description of the job performed by this job thread.
294    *
295    * @return A description of the job performed by this job thread.
296    */

297   public String JavaDoc getJobDescription()
298   {
299     return "This job can be used to perform repeated delete operations " +
300            "against an LDAP directory server to generate load and measure " +
301            "performance. It also provides the capability to measure the " +
302            "latency associated with replication while the deletes are in " +
303            "progress.";
304   }
305
306
307
308   /**
309    * Retrieves the name of the category in which this job class exists. This is
310    * used to help arrange the job classes in the administrative interface.
311    *
312    * @return The name of the category in which this job class exists.
313    */

314   public String JavaDoc getJobCategoryName()
315   {
316     return "LDAP";
317   }
318
319
320
321   /**
322    * Overrides the number of clients that may be used for this job to ensure
323    * that only a single client will be used.
324    *
325    * @return The number of clients that will always be used for this job.
326    */

327   public int overrideNumClients()
328   {
329     return 1;
330   }
331
332
333
334   /**
335    * Retrieve a parameter list that can be used to determine all of the
336    * customizeable options that are available for this job.
337    *
338    * @return A parameter list that can be used to determine all of the
339    * customizeable options that are available for this job.
340    */

341   public ParameterList getParameterStubs()
342   {
343     Parameter[] parameters = new Parameter[]
344     {
345       placeholder,
346       masterHostParameter,
347       masterPortParameter,
348       bindDNParameter,
349       bindPWParameter,
350       proxyAsDNParameter,
351       placeholder,
352       dnFileParameter,
353       entryDNParameter,
354       placeholder,
355       replicaHostParameter,
356       replicaPortParameter,
357       replicaEntryDNParameter,
358       replicaDelayParameter,
359       attributeParameter,
360       placeholder,
361       warmUpParameter,
362       coolDownParameter,
363       timeLimitParameter,
364       delayParameter,
365       placeholder,
366       disconnectParameter
367     };
368
369     return new ParameterList(parameters);
370   }
371
372
373
374   /**
375    * Retrieves the set of stat trackers that will be maintained by this job
376    * class. The stat trackers returned by this method do not have to actually
377    * contain any statistics -- the display name and stat tracker class should
378    * be the only information that callers of this method should rely upon. Note
379    * that this list can be different from the list of statistics actually
380    * collected by the job in some cases (e.g., if the job may not return all the
381    * stat trackers it advertises in all cases, or if the job may return stat
382    * trackers that it did not advertise), but it is a possibility that only the
383    * stat trackers returned by this method will be accessible for some features
384    * in the SLAMD server.
385    *
386    * @param clientID The client ID that should be used for the
387    * returned stat trackers.
388    * @param threadID The thread ID that should be used for the
389    * returned stat trackers.
390    * @param collectionInterval The collection interval that should be used for
391    * the returned stat trackers.
392    *
393    * @return The set of stat trackers that will be maintained by this job
394    * class.
395    */

396   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
397                                            int collectionInterval)
398   {
399     return new StatTracker[]
400     {
401       new IncrementalTracker(clientID, threadID, STAT_TRACKER_DELETE_COUNT,
402                              collectionInterval),
403       new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
404                       collectionInterval),
405       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
406                              collectionInterval),
407       new TimeTracker(clientID, threadID, STAT_TRACKER_REPLICA_LATENCY,
408                       collectionInterval),
409       new CategoricalTracker(clientID, threadID,
410                              STAT_TRACKER_CATEGORIZED_LATENCY,
411                              collectionInterval)
412     };
413   }
414
415
416
417   /**
418    * Retrieves the stat trackers that are maintained for this job thread.
419    *
420    * @return The stat trackers that are maintained for this job thread.
421    */

422   public StatTracker[] getStatTrackers()
423   {
424     if (reportLatencyTracker)
425     {
426       return new StatTracker[]
427       {
428         deleteCount,
429         deleteTime,
430         resultCodes,
431         latencyTime,
432         latencyCategories
433       };
434     }
435     else
436     {
437       return new StatTracker[]
438       {
439         deleteCount,
440         deleteTime,
441         resultCodes
442       };
443     }
444   }
445
446
447
448   /**
449    * Provides a means of validating the information used to schedule the job,
450    * including the scheduling information and list of parameters.
451    *
452    * @param numClients The number of clients that should be used to
453    * run the job.
454    * @param threadsPerClient The number of threads that should be created on
455    * each client to run the job.
456    * @param threadStartupDelay The delay in milliseconds that should be used
457    * when starting the client threads.
458    * @param startTime The time that the job should start running.
459    * @param stopTime The time that the job should stop running.
460    * @param duration The maximum length of time in seconds that the
461    * job should be allowed to run.
462    * @param collectionInterval The collection interval that should be used
463    * when gathering statistics for the job.
464    * @param parameters The set of parameters provided to this job that
465    * can be used to customize its behavior.
466    *
467    * @throws InvalidValueException If the provided information is not
468    * appropriate for running this job.
469    */

470   public void validateJobInfo(int numClients, int threadsPerClient,
471                               int threadStartupDelay, Date startTime,
472                               Date stopTime, int duration,
473                               int collectionInterval, ParameterList parameters)
474          throws InvalidValueException
475   {
476     if (numClients != 1)
477     {
478       throw new InvalidValueException("A DelRate job may only run on a " +
479                                       "single client.");
480     }
481
482     FileURLParameter dnFileParam =
483          parameters.getFileURLParameter(dnFileParameter.getName());
484     StringParameter dnParam =
485          parameters.getStringParameter(entryDNParameter.getName());
486
487     if ((dnFileParam == null) || (! dnFileParam.hasValue()))
488     {
489       if ((dnParam == null) || (! dnParam.hasValue()))
490       {
491         throw new InvalidValueException("Either a DN file or a DN pattern " +
492                                         "must be specified.");
493       }
494     }
495     else if ((dnParam != null) && (dnParam.hasValue()))
496     {
497       throw new InvalidValueException("You may not specify both a DN file " +
498                                       "and a DN pattern.");
499     }
500   }
501
502
503
504   /**
505    * Indicates whether this job class implements logic that makes it possible to
506    * test the validity of job parameters before scheduling the job for execution
507    * (e.g., to see if the server is reachable using the information provided).
508    *
509    * @return <CODE>true</CODE> if this job provides a means of testing the job
510    * parameters, or <CODE>false</CODE> if not.
511    */

512   public boolean providesParameterTest()
513   {
514     return true;
515   }
516
517
518
519   /**
520    * Provides a means of testing the provided job parameters to determine
521    * whether they are valid (e.g., to see if the server is reachable) before
522    * scheduling the job for execution. This method will be executed by the
523    * SLAMD server system itself and not by any of the clients.
524    *
525    * @param parameters The job parameters to be tested.
526    * @param outputMessages The lines of output that were generated as part of
527    * the testing process. Each line of output should
528    * be added to this list as a separate string, and
529    * empty strings (but not <CODE>null</CODE> values)
530    * are allowed to provide separation between
531    * different messages. No formatting should be
532    * provided for these messages, however, since they
533    * may be displayed in either an HTML or plain text
534    * interface.
535    *
536    * @return <CODE>true</CODE> if the test completed successfully, or
537    * <CODE>false</CODE> if not. Note that even if the test did not
538    * complete successfully, the user will be presented with a warning
539    * but will still be allowed to schedule the job using the provided
540    * parameters. This is necessary because the parameters may still be
541    * valid even if the server couldn't validate them at the time the
542    * job was scheduled (e.g., if the server wasn't running or could not
543    * be reached by the SLAMD server even though it could be by the
544    * clients).
545    */

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

859   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
860          throws UnableToRunException
861   {
862     // Initialize the latency check mutex and indicate that no latency tracking
863
// thread has yet been chosen.
864
latencyTrackerChosen = false;
865
866
867     // Get the address of the master directory server
868
masterHost = null;
869     masterHostParameter =
870          parameters.getStringParameter(masterHostParameter.getName());
871     if (masterHostParameter != null)
872     {
873       masterHost = masterHostParameter.getStringValue();
874     }
875
876     // Get the port for the master directory server
877
masterPort = 389;
878     masterPortParameter =
879          parameters.getIntegerParameter(masterPortParameter.getName());
880     if (masterPortParameter != null)
881     {
882       masterPort = masterPortParameter.getIntValue();
883     }
884
885     // Get the address of the replica directory server
886
replicaHost = null;
887     replicaHostParameter =
888          parameters.getStringParameter(replicaHostParameter.getName());
889     if (replicaHostParameter != null)
890     {
891       replicaHost = replicaHostParameter.getStringValue();
892     }
893
894     // Get the port for the replica directory server
895
replicaPort = 389;
896     replicaPortParameter =
897          parameters.getIntegerParameter(replicaPortParameter.getName());
898     if (replicaPortParameter != null)
899     {
900       replicaPort = replicaPortParameter.getIntValue();
901     }
902
903     // Get the bind DN for the target directory server
904
bindDN = "";
905     bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
906     if (bindDNParameter != null)
907     {
908       bindDN = bindDNParameter.getStringValue();
909     }
910
911     // Get the bind password for the target directory server
912
bindPassword = "";
913     bindPWParameter =
914          parameters.getPasswordParameter(bindPWParameter.getName());
915     if (bindPWParameter != null)
916     {
917       bindPassword = bindPWParameter.getStringValue();
918     }
919
920     // Get the DN of the proxy as user.
921
useProxyAuth = false;
922     proxyAsDNParameter =
923          parameters.getStringParameter(proxyAsDNParameter.getName());
924     if ((proxyAsDNParameter != null) && (proxyAsDNParameter.hasValue()))
925     {
926       useProxyAuth = true;
927       proxyAsDN = proxyAsDNParameter.getStringValue();
928     }
929
930     // Get the DNs of the entries to delete.
931
entryDNs = null;
932     dnFileParameter = parameters.getFileURLParameter(dnFileParameter.getName());
933     if ((dnFileParameter != null) && (dnFileParameter.hasValue()))
934     {
935       try
936       {
937         entryDNs = dnFileParameter.getNonBlankFileLines();
938         nextValue = 0;
939       }
940       catch (Exception JavaDoc e)
941       {
942         throw new UnableToRunException("ERROR: Unable to retrieve DN file " +
943                                        "data: " + e, e);
944       }
945     }
946
947     // Get the DN pattern.
948
dnInitial = null;
949     dnFinal = null;
950     dnMin = 0;
951     dnMax = Integer.MAX_VALUE;
952     entryDNParameter =
953          parameters.getStringParameter(entryDNParameter.getName());
954     if ((entryDNParameter != null) && (entryDNParameter.hasValue()))
955     {
956       String JavaDoc dnStr = entryDNParameter.getStringValue();
957
958       try
959       {
960         int openPos = dnStr.indexOf('[');
961         int colonPos = dnStr.indexOf(':', openPos);
962         int closePos = dnStr.indexOf(']', colonPos);
963
964         dnInitial = dnStr.substring(0, openPos);
965         dnFinal = dnStr.substring(closePos+1);
966
967         dnMin = Integer.parseInt(dnStr.substring(openPos+1, colonPos));
968         dnMax = Integer.parseInt(dnStr.substring(colonPos+1, closePos));
969         nextValue = dnMin;
970       }
971       catch (Exception JavaDoc e)
972       {
973         throw new UnableToRunException("ERROR: Unable to parse DN pattern: " +
974                                        e, e);
975       }
976     }
977
978     // Get the DN of the entry to use in the latency checks.
979
replicaEntryDN = null;
980     replicaEntryDNParameter =
981          parameters.getStringParameter(replicaEntryDNParameter.getName());
982     if (replicaEntryDNParameter != null)
983     {
984       replicaEntryDN = replicaEntryDNParameter.getStringValue();
985     }
986
987     // Get the delay between latency checks.
988
latencyDelay = 0;
989     replicaDelayParameter =
990          parameters.getIntegerParameter(replicaDelayParameter.getName());
991     if (replicaDelayParameter != null)
992     {
993       latencyDelay = replicaDelayParameter.getIntValue();
994     }
995
996     // Get the name of the attribute to modify for the latency checks.
997
attribute = null;
998     attributeParameter =
999          parameters.getStringParameter(attributeParameter.getName());
1000    if (attributeParameter != null)
1001    {
1002      attribute = attributeParameter.getStringValue();
1003    }
1004
1005    // Get the warm up time.
1006
warmUpTime = 0;
1007    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1008    if (warmUpParameter != null)
1009    {
1010      warmUpTime = warmUpParameter.getIntValue();
1011    }
1012
1013    // Get the cool down time.
1014
coolDownTime = 0;
1015    coolDownParameter =
1016         parameters.getIntegerParameter(coolDownParameter.getName());
1017    if (coolDownParameter != null)
1018    {
1019      coolDownTime = coolDownParameter.getIntValue();
1020    }
1021
1022    // Get the maximum add time limit.
1023
timeLimit = 0;
1024    timeLimitParameter =
1025         parameters.getIntegerParameter(timeLimitParameter.getName());
1026    if (timeLimitParameter != null)
1027    {
1028      timeLimit = timeLimitParameter.getIntValue();
1029    }
1030
1031    // Get the delay between requests.
1032
delay = 0;
1033    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1034    if (delayParameter != null)
1035    {
1036      delay = delayParameter.getIntValue();
1037    }
1038
1039    // Get the flag indicating whether we should disconnect after each delete.
1040
alwaysDisconnect = false;
1041    disconnectParameter =
1042         parameters.getBooleanParameter(disconnectParameter.getName());
1043    if (disconnectParameter != null)
1044    {
1045      alwaysDisconnect = disconnectParameter.getBooleanValue();
1046    }
1047
1048
1049    // Initialize the parent random number generator
1050
parentRandom = new Random();
1051  }
1052
1053
1054
1055  /**
1056   * Initializes this job thread to be used to actually run the job on the
1057   * client. The provided parameter list should be processed to customize the
1058   * behavior of this job thread, and any other initialization that needs to be
1059   * done in order for the job to run should be performed here as well.
1060   *
1061   * @param clientID The client ID for this job thread.
1062   * @param threadID The thread ID for this job thread.
1063   * @param collectionInterval The length of time in seconds to use as the
1064   * statistics collection interval.
1065   * @param parameters The set of parameters provided to this job that
1066   * can be used to customize its behavior.
1067   *
1068   * @throws UnableToRunException If a problem occurs that prevents the thread
1069   * from being able to run properly.
1070   */

1071  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1072                               int collectionInterval, ParameterList parameters)
1073         throws UnableToRunException
1074  {
1075    // Set up the stat trackers
1076
deleteCount = new IncrementalTracker(clientID, threadID,
1077                                         STAT_TRACKER_DELETE_COUNT,
1078                                         collectionInterval);
1079    deleteTime = new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
1080                                  collectionInterval);
1081    resultCodes = new CategoricalTracker(clientID, threadID,
1082                                         STAT_TRACKER_RESULT_CODES,
1083                                         collectionInterval);
1084
1085
1086    // Enable real-time reporting of the data for these stat trackers.
1087
RealTimeStatReporter statReporter = getStatReporter();
1088    if (statReporter != null)
1089    {
1090      String JavaDoc jobID = getJobID();
1091      deleteCount.enableRealTimeStats(statReporter, jobID);
1092      deleteTime.enableRealTimeStats(statReporter, jobID);
1093    }
1094
1095
1096    // Initialize the random number generator for this thread.
1097
random = new Random(parentRandom.nextLong());
1098
1099
1100    // See if this thread should be used to report the replica latency
1101
// information. If so, then start the latency check threads.
1102
if ((! latencyTrackerChosen) && (getClientNumber() == 0))
1103    {
1104      latencyCheckMutex = new Object JavaDoc();
1105      latencyTrackerChosen = true;
1106      reportLatencyTracker = true;
1107
1108      // Create the latency timer stat tracker.
1109
latencyTime = new TimeTracker(clientID, threadID,
1110                                    STAT_TRACKER_REPLICA_LATENCY,
1111                                    collectionInterval);
1112      if (statReporter != null)
1113      {
1114        latencyTime.enableRealTimeStats(statReporter, getJobID());
1115      }
1116
1117      // Create the latency categories stat tracker.
1118
latencyCategories =
1119           new CategoricalTracker(clientID, threadID,
1120                                  STAT_TRACKER_CATEGORIZED_LATENCY,
1121                                  collectionInterval);
1122
1123      // Create the latency thread that will make changes to the master server.
1124
try
1125      {
1126        masterThread =
1127             new LatencyCheckMasterThread(this, masterHost, masterPort, bindDN,
1128                                          bindPassword, replicaEntryDN,
1129                                          attribute, latencyDelay);
1130      }
1131      catch (LDAPException le)
1132      {
1133        throw new UnableToRunException("Could not create the master latency " +
1134                                       "thread: " + le, le);
1135      }
1136
1137      // Create the latency thread that will read changes from the replica.
1138
try
1139      {
1140        replicaThread =
1141             new LatencyCheckReplicaThread(this, replicaHost, replicaPort,
1142                                           bindDN, bindPassword,
1143                                           replicaEntryDN);
1144      }
1145      catch (LDAPException le)
1146      {
1147        throw new UnableToRunException("Could not create the replica latency " +
1148                                       "thread: " + le, le);
1149      }
1150
1151      // Start the latency check threads.
1152
masterThread.start();
1153      replicaThread.start();
1154    }
1155    else
1156    {
1157      reportLatencyTracker = false;
1158    }
1159  }
1160
1161
1162
1163  /**
1164   * Perform the work of this job thread by establishing the connection(s) to
1165   * the directory server and issuing all the appropriate queries. The job will
1166   * continue until the specified number of iterations have been performed, the
1167   * stop time has been reached, the maximum duration has been reached, or the
1168   * SLAMD server indicates that a stop has been requested.
1169   */

1170  public void runJob()
1171  {
1172    // Determine the range of time for which we should collect statistics.
1173
long currentTime = System.currentTimeMillis();
1174    boolean collectingStats = false;
1175    long startCollectingTime = currentTime + (1000 * warmUpTime);
1176    long stopCollectingTime = Long.MAX_VALUE;
1177    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1178    {
1179      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1180    }
1181
1182    // Set a variable that we can use to determine if the connection is alive or
1183
// not
1184
boolean connected = false;
1185
1186    // Set a variable that should be used to determine whether all the entries
1187
// have been deleted yet or not.
1188
boolean allRemoved = false;
1189
1190    // Set a variable that can be used to determine how long we should sleep
1191
// between deletes.
1192
long deleteStartTime = 0;
1193
1194    // Create a variable that we will use for the LDAP connection
1195
conn = new LDAPConnection();
1196
1197
1198    // Create a loop that will run until it needs to stop
1199
while ((! shouldStop()) && (! allRemoved))
1200    {
1201      currentTime = System.currentTimeMillis();
1202      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1203          (currentTime < stopCollectingTime))
1204      {
1205        // Tell the stat trackers that they should start tracking now
1206
deleteCount.startTracker();
1207        deleteTime.startTracker();
1208        resultCodes.startTracker();
1209
1210        if (reportLatencyTracker)
1211        {
1212          latencyTime.startTracker();
1213          latencyCategories.startTracker();
1214          replicaThread.startChecking();
1215          masterThread.startChecking();
1216        }
1217
1218        collectingStats = true;
1219      }
1220      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1221      {
1222        deleteCount.stopTracker();
1223        deleteTime.stopTracker();
1224        resultCodes.stopTracker();
1225
1226        if (reportLatencyTracker)
1227        {
1228          latencyTime.stopTracker();
1229          latencyCategories.stopTracker();
1230          replicaThread.stopAndWait();
1231          masterThread.stopAndWait();
1232        }
1233
1234        collectingStats = false;
1235      }
1236
1237      // If the connection is currently not connected, then establish it
1238
if (! connected)
1239      {
1240        try
1241        {
1242          conn.connect(3, masterHost, masterPort, bindDN, bindPassword);
1243          connected = true;
1244        }
1245        catch (LDAPException le)
1246        {
1247          logMessage("ERROR -- Could not connect to " + masterHost + ":" +
1248                           masterPort + " (" + le + ") -- aborting thread");
1249          if (collectingStats)
1250          {
1251            resultCodes.increment(String.valueOf(le.getLDAPResultCode()));
1252          }
1253          indicateStoppedDueToError();
1254          break;
1255        }
1256      }
1257
1258      LDAPConstraints constraints = conn.getConstraints();
1259      if (useProxyAuth)
1260      {
1261        LDAPProxiedAuthControl proxyAuthControl =
1262             new LDAPProxiedAuthControl(proxyAsDN, true);
1263        constraints.setServerControls(proxyAuthControl);
1264      }
1265      constraints.setTimeLimit(1000 * timeLimit);
1266
1267
1268      // Create a flag used to determine if the add was successful.
1269
String JavaDoc dnToDelete = getEntryDN();
1270      if (dnToDelete == null)
1271      {
1272        allRemoved = true;
1273      }
1274      else
1275      {
1276        // Record the current time as the start of the delete.
1277
if (collectingStats)
1278        {
1279          deleteTime.startTimer();
1280        }
1281        if (delay > 0)
1282        {
1283          deleteStartTime = System.currentTimeMillis();
1284        }
1285
1286        // Perform the add
1287
int resultCode = LDAPException.SUCCESS;
1288        try
1289        {
1290          conn.delete(dnToDelete, constraints);
1291        }
1292        catch (LDAPException le)
1293        {
1294          resultCode = le.getLDAPResultCode();
1295        }
1296
1297
1298        // Record the current time as the end of the delete.
1299
if (collectingStats)
1300        {
1301          deleteCount.increment();
1302          deleteTime.stopTimer();
1303          resultCodes.increment(String.valueOf(resultCode));
1304        }
1305      }
1306
1307      // If the connection should be broken, then do so
1308
if (alwaysDisconnect)
1309      {
1310        try
1311        {
1312          conn.disconnect();
1313        } catch (LDAPException le) {}
1314        connected = false;
1315      }
1316
1317      // If we need to sleep, then do so
1318
if ((delay > 0) && (! shouldStop()))
1319      {
1320        long now = System.currentTimeMillis();
1321        long sleepTime = delay - (now - deleteStartTime);
1322        if (sleepTime > 0)
1323        {
1324          try
1325          {
1326            Thread.sleep(sleepTime);
1327          } catch (InterruptedException JavaDoc ie) {}
1328        }
1329      }
1330    }
1331
1332
1333    // If the connection is still established, then close it
1334
try
1335    {
1336      conn.disconnect();
1337    } catch (LDAPException le) {}
1338
1339
1340    // Tell the stat trackers that they should stop tracking
1341
if (collectingStats)
1342    {
1343      deleteCount.stopTracker();
1344      deleteTime.stopTimer();
1345      resultCodes.stopTracker();
1346
1347      if (reportLatencyTracker)
1348      {
1349        latencyTime.stopTracker();
1350        latencyCategories.stopTracker();
1351        replicaThread.stopAndWait();
1352        masterThread.stopAndWait();
1353      }
1354    }
1355  }
1356
1357
1358
1359  /**
1360   * Attempts to force this thread to exit by closing the connection to the
1361   * directory server and setting it to <CODE>null</CODE>.
1362   */

1363  public void destroy()
1364  {
1365    if (conn != null)
1366    {
1367      try
1368      {
1369        conn.disconnect();
1370      } catch (Exception JavaDoc e) {}
1371
1372      conn = null;
1373    }
1374
1375    if (masterThread != null)
1376    {
1377      masterThread.masterThread.interrupt();
1378
1379      try
1380      {
1381        masterThread.connection.disconnect();
1382      } catch (Exception JavaDoc e) {}
1383
1384      masterThread.connection = null;
1385      masterThread = null;
1386    }
1387
1388    if (replicaThread != null)
1389    {
1390      replicaThread.replicaThread.interrupt();
1391
1392      try
1393      {
1394        replicaThread.connection.disconnect();
1395      } catch (Exception JavaDoc e) {}
1396
1397      replicaThread.connection = null;
1398      replicaThread = null;
1399    }
1400  }
1401
1402
1403
1404  /**
1405   * Ensures that the master and replica check threads are properly stopped.
1406   */

1407  public void finalizeClient()
1408  {
1409    masterThread.stopAndWait();
1410    replicaThread.stopAndWait();
1411  }
1412
1413
1414
1415  /**
1416   * Creates a randomly-generated LDAP entry to be added to the directory.
1417   *
1418   * @return The randomly-generated entry.
1419   */

1420  public String JavaDoc getEntryDN()
1421  {
1422    if (entryDNs == null)
1423    {
1424      int value = nextValue++;
1425      if (value > dnMax)
1426      {
1427        return null;
1428      }
1429
1430      return dnInitial + value + dnFinal;
1431    }
1432    else
1433    {
1434      int index = nextValue++;
1435      if (index < entryDNs.length)
1436      {
1437        return entryDNs[index];
1438      }
1439      else
1440      {
1441        return null;
1442      }
1443    }
1444  }
1445}
1446
1447
Popular Tags