KickJava   Java API By Example, From Geeks To Geeks.

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


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 add
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 AddRateWithReplicaLatencyJobClass
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 add.
43    */

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

52   public static final String JavaDoc STAT_TRACKER_ADD_COUNT = "Adds 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 default set of attributes to include in the entries that are generated.
91    */

92   public static final String JavaDoc[] DEFAULT_ATTR_NAMES = new String JavaDoc[]
93   {
94     "givenname",
95     "sn",
96     "cn",
97     "uid",
98     "userpassword",
99     "mail",
100   };
101
102
103
104   /**
105    * The default set of objectclass values to create.
106    */

107   public static final String JavaDoc[] OBJECTCLASS_VALUES = new String JavaDoc[]
108   {
109     "top",
110     "person",
111     "organizationalPerson",
112     "inetOrgPerson",
113     "extensibleObject"
114   };
115
116
117
118   // The parameter that indicates whether to disconnect after each add
119
BooleanParameter disconnectParameter =
120        new BooleanParameter("disconnect", "Always Disconnect",
121                             "Indicates whether to close the connection after " +
122                             "each add", false);
123
124   // The parmeter that specifies the cool-down time in seconds.
125
IntegerParameter coolDownParameter =
126        new IntegerParameter("cool_down", "Cool Down Time",
127                             "The time in seconds that the job should " +
128                             "continue adding after ending statistics " +
129                             "collection.", true, 0, true, 0, false, 0);
130
131   // The parameter that indicates the delay that should be used between each
132
// request sent by a thread.
133
IntegerParameter delayParameter =
134        new IntegerParameter("delay", "Time Between Requests (ms)",
135                             "Specifies the length of time in milliseconds " +
136                             "each thread should wait between add " +
137                             "requests. Note that this delay will be " +
138                             "between consecutive requests and not between " +
139                             "the response of one operation and the request " +
140                             "for the next. If an add takes longer than " +
141                             "this length of time, then there will be no delay.",
142                             true, 0, true, 0, false, 0);
143
144   // The parameter that indicates the minimum length of time to sleep between
145
// modifications of the latency check entry.
146
IntegerParameter replicaDelayParameter =
147        new IntegerParameter("latency_delay", "Time Between Latency Checks (ms)",
148                             "Specifies the minimum length of time in " +
149                             "milliseconds that should pass between latency " +
150                             "checks. If a replicated operation takes longer " +
151                             "than this length of time, then there will be no " +
152                             "delay.", true, 0, true, 0, false, 0);
153
154   // The parameter that indicates the length of the generated attribute values.
155
IntegerParameter lengthParameter =
156     new IntegerParameter("value_length", "Generated Value Length",
157                          "Specifies the number of characters that should be " +
158                          "included in the generated values of the attriubtes.",
159                          true, 80, true, 1, false, 0);
160
161   // The parameter that indicates the port number for the master directory
162
IntegerParameter masterPortParameter =
163        new IntegerParameter("masterport", "Master Directory Port",
164                             "The port number for the master directory server",
165                             true, 389, true, 1, true, 65535);
166
167   // The parameter that indicates the port number for the replica directory
168
IntegerParameter replicaPortParameter =
169        new IntegerParameter("replicaport", "Replica Directory Port",
170                             "The port number for the replica directory server",
171                             true, 389, true, 1, true, 65535);
172
173   // The parameter that specifies the starting number for the RDN values.
174
IntegerParameter rdnStartParameter =
175        new IntegerParameter("rdn_start", "Initial RDN Value Number",
176                             "The number to use as the value of the RDN " +
177                             "attribute for the first entry to create", true, 1,
178                             false, 0, false, 0);
179
180   // The parameter that specifies the ending number for the RDN values.
181
IntegerParameter rdnEndParameter =
182        new IntegerParameter("rdn_end", "Final RDN Value Number",
183                             "The number to use as the value of the RDN " +
184                             "attribute for the last entry to create", false, 0,
185                             false, 0, false, 0);
186
187   // The parameter that indicates the maximum time limit for add operations.
188
IntegerParameter timeLimitParameter =
189        new IntegerParameter("time_limit", "Add Time Limit",
190                             "The maximum length of time in seconds that the " +
191                             "thread should wait for a add operation to be " +
192                             "performed before cancelling it and trying " +
193                             "another.", false, 0, true, 0, false, 0);
194
195   // The parmeter that specifies the cool-down time in seconds.
196
IntegerParameter warmUpParameter =
197        new IntegerParameter("warm_up", "Warm Up Time",
198                             "The time in seconds that the job should " +
199                             "add before beginning statistics collection.",
200                             true, 0, true, 0, false, 0);
201
202   // The names of additional attributes to add to the entries that are created.
203
MultiLineTextParameter extraAttrsParameter =
204        new MultiLineTextParameter("extra_attrs", "Additional Attributes",
205                                   "The names of additional attributes to " +
206                                   "include in the entries that will be " +
207                                   "generated. By default, inetOrgPerson " +
208                                   "entries will be created, with attributes " +
209                                   "of givenName, sn, cn, uid, userPassword, " +
210                                   "and mail, but they will also include the " +
211                                   "extensibleObject objectclass so that any " +
212                                   "additional attributes may be used. Each " +
213                                   "attribute specified will be given a " +
214                                   "value of a string of 80 randomly-chosen " +
215                                   "characters.", null, false);
216
217   // The placeholder parameter used as a spacer in the admin interface.
218
PlaceholderParameter placeholder = new PlaceholderParameter();
219
220   // The parameter that specifies the attribute to modify
221
StringParameter attributeParameter =
222        new StringParameter("attribute", "Attribute to Modify",
223                            "The attribute to modify for the latency checks",
224                            true, "description");
225
226   // The parameter that indicates the DN to use when binding to the server
227
StringParameter bindDNParameter =
228        new StringParameter("binddn", "Bind DN",
229                            "The DN to use to bind to the server", false, "");
230
231   // The parameter that indicates the base below which entries will be added.
232
StringParameter baseDNParameter =
233        new StringParameter("basedn", "Base DN ",
234                            "The base below which to add the entries",
235                            true, "");
236
237   // The parameter that indicates the address of the master directory server
238
StringParameter masterHostParameter =
239        new StringParameter("masterhost", "Master Directory Host",
240                            "The DNS hostname or IP address of the master " +
241                            "directory server", true, "");
242
243   // The parameter that indicates the address of the replica directory server
244
StringParameter replicaHostParameter =
245        new StringParameter("replicahost", "Replica Directory Host",
246                            "The DNS hostname or IP address of the replica " +
247                            "directory server", true, "");
248
249   // The parameter that specifies the DN of the entry to watch for replication
250
// latency
251
StringParameter replicaEntryDNParameter =
252        new StringParameter("replica_entry_dn", "Latency Check Entry DN",
253                            "The DN of the entry that should be periodically " +
254                            "modified to measure the latency of replication. " +
255                            "Note that this DN must not be the same as " +
256                            "the DN of any of the entries to modify, nor " +
257                            "should this entry be modified by any external " +
258                            "process during the test.", true, "");
259
260   // The parameter that indicates the DN to use to proxy the adds.
261
StringParameter proxyAsDNParameter =
262        new StringParameter("proxy_as_dn", "Proxy As DN",
263                            "The DN of the user whose credentials should be " +
264                            "used to perform the adds through the use " +
265                            "of the proxied authorization control.", false, "");
266
267   // The parameter that indicates the RDN attribute for the new entries.
268
StringParameter rdnAttrParameter =
269        new StringParameter("rdn_attr", "RDN Attribute",
270                            "The RDN attribute to use when creating the " +
271                            "entries.", true, "uid");
272
273   // The parameter that indicates the bind password
274
PasswordParameter bindPWParameter =
275        new PasswordParameter("bindpw", "Bind Password",
276                              "The password for the bind DN", false, "");
277
278
279   // Instance variables that correspond to the parameter values
280
static boolean alwaysDisconnect;
281   static boolean useProxyAuth;
282   static int coolDownTime;
283   static int latencyDelay;
284   static int maxRDNValue;
285   static int minRDNValue;
286   static int masterPort;
287   static int replicaPort;
288   static int nextValue;
289   static int timeLimit;
290   static int valueLength;
291   static int warmUpTime;
292   static long delay;
293   static String JavaDoc attribute;
294   static String JavaDoc baseDN;
295   static String JavaDoc bindDN;
296   static String JavaDoc bindPassword;
297   static String JavaDoc masterHost;
298   static String JavaDoc replicaHost;
299   static String JavaDoc replicaEntryDN;
300   static String JavaDoc proxyAsDN;
301   static String JavaDoc rdnAttr;
302   static String JavaDoc[] attrsToInclude;
303
304
305   // The connection to the directory server over which the adds will be
306
// performed.
307
LDAPConnection conn;
308
309
310   // Variables used for status counters
311
CategoricalTracker resultCodes;
312   IncrementalTracker addCount;
313   TimeTracker addTime;
314
315
316   // Variables used for tracking replication latency.
317
static boolean latencyTrackerChosen;
318   boolean reportLatencyTracker;
319   LatencyCheckMasterThread masterThread;
320   LatencyCheckReplicaThread replicaThread;
321
322
323   // One random number generator for use throughout the client and another to
324
// use for only the current thread.
325
static Random parentRandom;
326   Random random;
327
328
329
330
331   /**
332    * The default constructor used to create a new instance of the add thread.
333    * The only thing it should do is to invoke the superclass constructor. All
334    * other initialization should be performed in the <CODE>initialize</CODE>
335    * method.
336    */

337   public AddRateWithReplicaLatencyJobClass()
338   {
339     super();
340   }
341
342
343
344   /**
345    * Retrieves the name of the job performed by this job thread.
346    *
347    * @return The name of the job performed by this job thread.
348    */

349   public String JavaDoc getJobName()
350   {
351     return "LDAP AddRate with Replica Latency";
352   }
353
354
355
356   /**
357    * Retrieves a description of the job performed by this job thread.
358    *
359    * @return A description of the job performed by this job thread.
360    */

361   public String JavaDoc getJobDescription()
362   {
363     return "This job can be used to perform repeated add operations against " +
364            "an LDAP directory server to generate load and measure " +
365            "performance. It also provides the capability to measure the " +
366            "latency associated with replication while the adds are in " +
367            "progress.";
368   }
369
370
371
372   /**
373    * Retrieves the name of the category in which this job class exists. This is
374    * used to help arrange the job classes in the administrative interface.
375    *
376    * @return The name of the category in which this job class exists.
377    */

378   public String JavaDoc getJobCategoryName()
379   {
380     return "LDAP";
381   }
382
383
384
385   /**
386    * Overrides the number of clients that may be used for this job to ensure
387    * that only a single client will be used.
388    *
389    * @return The number of clients that will always be used for this job.
390    */

391   public int overrideNumClients()
392   {
393     return 1;
394   }
395
396
397
398   /**
399    * Retrieve a parameter list that can be used to determine all of the
400    * customizeable options that are available for this job.
401    *
402    * @return A parameter list that can be used to determine all of the
403    * customizeable options that are available for this job.
404    */

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

464   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
465                                            int collectionInterval)
466   {
467     return new StatTracker[]
468     {
469       new IncrementalTracker(clientID, threadID, STAT_TRACKER_ADD_COUNT,
470                              collectionInterval),
471       new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
472                       collectionInterval),
473       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
474                              collectionInterval),
475       new TimeTracker(clientID, threadID, STAT_TRACKER_REPLICA_LATENCY,
476                       collectionInterval),
477       new CategoricalTracker(clientID, threadID,
478                              STAT_TRACKER_CATEGORIZED_LATENCY,
479                              collectionInterval)
480     };
481   }
482
483
484
485   /**
486    * Retrieves the stat trackers that are maintained for this job thread.
487    *
488    * @return The stat trackers that are maintained for this job thread.
489    */

490   public StatTracker[] getStatTrackers()
491   {
492     if (reportLatencyTracker)
493     {
494       return new StatTracker[]
495       {
496         addCount,
497         addTime,
498         resultCodes,
499         latencyTime,
500         latencyCategories
501       };
502     }
503     else
504     {
505       return new StatTracker[]
506       {
507         addCount,
508         addTime,
509         resultCodes
510       };
511     }
512   }
513
514
515
516   /**
517    * Provides a means of validating the information used to schedule the job,
518    * including the scheduling information and list of parameters.
519    *
520    * @param numClients The number of clients that should be used to
521    * run the job.
522    * @param threadsPerClient The number of threads that should be created on
523    * each client to run the job.
524    * @param threadStartupDelay The delay in milliseconds that should be used
525    * when starting the client threads.
526    * @param startTime The time that the job should start running.
527    * @param stopTime The time that the job should stop running.
528    * @param duration The maximum length of time in seconds that the
529    * job should be allowed to run.
530    * @param collectionInterval The collection interval that should be used
531    * when gathering statistics for the job.
532    * @param parameters The set of parameters provided to this job that
533    * can be used to customize its behavior.
534    *
535    * @throws InvalidValueException If the provided information is not
536    * appropriate for running this job.
537    */

538   public void validateJobInfo(int numClients, int threadsPerClient,
539                               int threadStartupDelay, Date startTime,
540                               Date stopTime, int duration,
541                               int collectionInterval, ParameterList parameters)
542          throws InvalidValueException
543   {
544     if (numClients != 1)
545     {
546       throw new InvalidValueException("An AddRate job may only run on a " +
547                                       "single client.");
548     }
549   }
550
551
552
553   /**
554    * Indicates whether this job class implements logic that makes it possible to
555    * test the validity of job parameters before scheduling the job for execution
556    * (e.g., to see if the server is reachable using the information provided).
557    *
558    * @return <CODE>true</CODE> if this job provides a means of testing the job
559    * parameters, or <CODE>false</CODE> if not.
560    */

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

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

988   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
989          throws UnableToRunException
990   {
991     // Initialize the latency check mutex and indicate that no latency tracking
992
// thread has yet been chosen.
993
latencyTrackerChosen = false;
994
995
996     // Get the address of the master directory server
997
masterHost = null;
998     masterHostParameter =
999          parameters.getStringParameter(masterHostParameter.getName());
1000    if (masterHostParameter != null)
1001    {
1002      masterHost = masterHostParameter.getStringValue();
1003    }
1004
1005    // Get the port for the master directory server
1006
masterPort = 389;
1007    masterPortParameter =
1008         parameters.getIntegerParameter(masterPortParameter.getName());
1009    if (masterPortParameter != null)
1010    {
1011      masterPort = masterPortParameter.getIntValue();
1012    }
1013
1014    // Get the address of the replica directory server
1015
replicaHost = null;
1016    replicaHostParameter =
1017         parameters.getStringParameter(replicaHostParameter.getName());
1018    if (replicaHostParameter != null)
1019    {
1020      replicaHost = replicaHostParameter.getStringValue();
1021    }
1022
1023    // Get the port for the replica directory server
1024
replicaPort = 389;
1025    replicaPortParameter =
1026         parameters.getIntegerParameter(replicaPortParameter.getName());
1027    if (replicaPortParameter != null)
1028    {
1029      replicaPort = replicaPortParameter.getIntValue();
1030    }
1031
1032    // Get the bind DN for the target directory server
1033
bindDN = "";
1034    bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
1035    if (bindDNParameter != null)
1036    {
1037      bindDN = bindDNParameter.getStringValue();
1038    }
1039
1040    // Get the bind password for the target directory server
1041
bindPassword = "";
1042    bindPWParameter =
1043         parameters.getPasswordParameter(bindPWParameter.getName());
1044    if (bindPWParameter != null)
1045    {
1046      bindPassword = bindPWParameter.getStringValue();
1047    }
1048
1049    // Get the DN of the proxy as user.
1050
useProxyAuth = false;
1051    proxyAsDNParameter =
1052         parameters.getStringParameter(proxyAsDNParameter.getName());
1053    if ((proxyAsDNParameter != null) && (proxyAsDNParameter.hasValue()))
1054    {
1055      useProxyAuth = true;
1056      proxyAsDN = proxyAsDNParameter.getStringValue();
1057    }
1058
1059    // Get the base DN under which to add the entries.
1060
baseDN = null;
1061    baseDNParameter = parameters.getStringParameter(baseDNParameter.getName());
1062    if ((baseDNParameter != null) && (baseDNParameter.hasValue()))
1063    {
1064      baseDN = baseDNParameter.getStringValue();
1065    }
1066
1067    // Get the name of the RDN attribute to use.
1068
rdnAttr = "uid";
1069    rdnAttrParameter =
1070         parameters.getStringParameter(rdnAttrParameter.getName());
1071    if ((rdnAttrParameter != null) && (rdnAttrParameter.hasValue()))
1072    {
1073      rdnAttr = rdnAttrParameter.getStringValue().toLowerCase();
1074    }
1075
1076    // Get the initial RDN value to create.
1077
minRDNValue = 0;
1078    rdnStartParameter =
1079         parameters.getIntegerParameter(rdnStartParameter.getName());
1080    if ((rdnStartParameter != null) && (rdnStartParameter.hasValue()))
1081    {
1082      minRDNValue = rdnStartParameter.getIntValue();
1083    }
1084    nextValue = minRDNValue;
1085
1086    // Get the final RDN value to create.
1087
maxRDNValue = Integer.MAX_VALUE;
1088    rdnEndParameter = parameters.getIntegerParameter(rdnEndParameter.getName());
1089    if ((rdnEndParameter != null) && (rdnEndParameter.hasValue()))
1090    {
1091      maxRDNValue = rdnEndParameter.getIntValue();
1092      if (maxRDNValue <= 0)
1093      {
1094        maxRDNValue = Integer.MAX_VALUE;
1095      }
1096    }
1097
1098    // Get the length to use for the attribute values.
1099
valueLength = 80;
1100    lengthParameter = parameters.getIntegerParameter(lengthParameter.getName());
1101    if ((lengthParameter != null) && (lengthParameter.hasValue()))
1102    {
1103      valueLength = lengthParameter.getIntValue();
1104    }
1105
1106    // Get the extra attributes to include in the entry.
1107
attrsToInclude = DEFAULT_ATTR_NAMES;
1108    extraAttrsParameter =
1109         parameters.getMultiLineTextParameter(extraAttrsParameter.getName());
1110    if ((extraAttrsParameter != null) && (extraAttrsParameter.hasValue()))
1111    {
1112      String JavaDoc[] extraAttrs = extraAttrsParameter.getNonBlankLines();
1113      String JavaDoc[] tmpAttrs = new String JavaDoc[attrsToInclude.length + extraAttrs.length];
1114      System.arraycopy(attrsToInclude, 0, tmpAttrs, 0, attrsToInclude.length);
1115      for (int i=attrsToInclude.length, j=0; i < tmpAttrs.length; i++,j++)
1116      {
1117        tmpAttrs[i] = extraAttrs[j].toLowerCase();
1118      }
1119
1120      attrsToInclude = tmpAttrs;
1121    }
1122
1123    // Get the DN of the entry to use in the latency checks.
1124
replicaEntryDN = null;
1125    replicaEntryDNParameter =
1126         parameters.getStringParameter(replicaEntryDNParameter.getName());
1127    if (replicaEntryDNParameter != null)
1128    {
1129      replicaEntryDN = replicaEntryDNParameter.getStringValue();
1130    }
1131
1132    // Get the delay between latency checks.
1133
latencyDelay = 0;
1134    replicaDelayParameter =
1135         parameters.getIntegerParameter(replicaDelayParameter.getName());
1136    if (replicaDelayParameter != null)
1137    {
1138      latencyDelay = replicaDelayParameter.getIntValue();
1139    }
1140
1141    // Get the name of the attribute to modify for the latency checks.
1142
attribute = null;
1143    attributeParameter =
1144         parameters.getStringParameter(attributeParameter.getName());
1145    if (attributeParameter != null)
1146    {
1147      attribute = attributeParameter.getStringValue();
1148    }
1149
1150    // Get the warm up time.
1151
warmUpTime = 0;
1152    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1153    if (warmUpParameter != null)
1154    {
1155      warmUpTime = warmUpParameter.getIntValue();
1156    }
1157
1158    // Get the cool down time.
1159
coolDownTime = 0;
1160    coolDownParameter =
1161         parameters.getIntegerParameter(coolDownParameter.getName());
1162    if (coolDownParameter != null)
1163    {
1164      coolDownTime = coolDownParameter.getIntValue();
1165    }
1166
1167    // Get the maximum add time limit.
1168
timeLimit = 0;
1169    timeLimitParameter =
1170         parameters.getIntegerParameter(timeLimitParameter.getName());
1171    if (timeLimitParameter != null)
1172    {
1173      timeLimit = timeLimitParameter.getIntValue();
1174    }
1175
1176    // Get the delay between requests.
1177
delay = 0;
1178    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1179    if (delayParameter != null)
1180    {
1181      delay = delayParameter.getIntValue();
1182    }
1183
1184    // Get the flag indicating whether we should disconnect after each add
1185
alwaysDisconnect = false;
1186    disconnectParameter =
1187         parameters.getBooleanParameter(disconnectParameter.getName());
1188    if (disconnectParameter != null)
1189    {
1190      alwaysDisconnect = disconnectParameter.getBooleanValue();
1191    }
1192
1193
1194    // Initialize the parent random number generator
1195
parentRandom = new Random();
1196  }
1197
1198
1199
1200  /**
1201   * Initializes this job thread to be used to actually run the job on the
1202   * client. The provided parameter list should be processed to customize the
1203   * behavior of this job thread, and any other initialization that needs to be
1204   * done in order for the job to run should be performed here as well.
1205   *
1206   * @param clientID The client ID for this job thread.
1207   * @param threadID The thread ID for this job thread.
1208   * @param collectionInterval The length of time in seconds to use as the
1209   * statistics collection interval.
1210   * @param parameters The set of parameters provided to this job that
1211   * can be used to customize its behavior.
1212   *
1213   * @throws UnableToRunException If a problem occurs that prevents the thread
1214   * from being able to run properly.
1215   */

1216  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1217                               int collectionInterval, ParameterList parameters)
1218         throws UnableToRunException
1219  {
1220    // Set up the stat trackers
1221
addCount = new IncrementalTracker(clientID, threadID,
1222                                      STAT_TRACKER_ADD_COUNT,
1223                                      collectionInterval);
1224    addTime = new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
1225                              collectionInterval);
1226    resultCodes = new CategoricalTracker(clientID, threadID,
1227                                         STAT_TRACKER_RESULT_CODES,
1228                                         collectionInterval);
1229
1230
1231    // Enable real-time reporting of the data for these stat trackers.
1232
RealTimeStatReporter statReporter = getStatReporter();
1233    if (statReporter != null)
1234    {
1235      String JavaDoc jobID = getJobID();
1236      addCount.enableRealTimeStats(statReporter, jobID);
1237      addTime.enableRealTimeStats(statReporter, jobID);
1238    }
1239
1240
1241    // Initialize the random number generator for this thread.
1242
random = new Random(parentRandom.nextLong());
1243
1244
1245    // See if this thread should be used to report the replica latency
1246
// information. If so, then start the latency check threads.
1247
if ((! latencyTrackerChosen) && (getClientNumber() == 0))
1248    {
1249      latencyCheckMutex = new Object JavaDoc();
1250      latencyTrackerChosen = true;
1251      reportLatencyTracker = true;
1252
1253      // Create the latency timer stat tracker.
1254
latencyTime = new TimeTracker(clientID, threadID,
1255                                    STAT_TRACKER_REPLICA_LATENCY,
1256                                    collectionInterval);
1257      if (statReporter != null)
1258      {
1259        latencyTime.enableRealTimeStats(statReporter, getJobID());
1260      }
1261
1262      // Create the latency categories stat tracker.
1263
latencyCategories =
1264           new CategoricalTracker(clientID, threadID,
1265                                  STAT_TRACKER_CATEGORIZED_LATENCY,
1266                                  collectionInterval);
1267
1268      // Create the latency thread that will make changes to the master server.
1269
try
1270      {
1271        masterThread =
1272             new LatencyCheckMasterThread(this, masterHost, masterPort, bindDN,
1273                                          bindPassword, replicaEntryDN,
1274                                          attribute, latencyDelay);
1275      }
1276      catch (LDAPException le)
1277      {
1278        throw new UnableToRunException("Could not create the master latency " +
1279                                       "thread: " + le, le);
1280      }
1281
1282      // Create the latency thread that will read changes from the replica.
1283
try
1284      {
1285        replicaThread =
1286             new LatencyCheckReplicaThread(this, replicaHost, replicaPort,
1287                                           bindDN, bindPassword,
1288                                           replicaEntryDN);
1289      }
1290      catch (LDAPException le)
1291      {
1292        throw new UnableToRunException("Could not create the replica latency " +
1293                                       "thread: " + le, le);
1294      }
1295
1296      // Start the latency check threads.
1297
masterThread.start();
1298      replicaThread.start();
1299    }
1300    else
1301    {
1302      reportLatencyTracker = false;
1303    }
1304  }
1305
1306
1307
1308  /**
1309   * Perform the work of this job thread by establishing the connection(s) to
1310   * the directory server and issuing all the appropriate queries. The job will
1311   * continue until the specified number of iterations have been performed, the
1312   * stop time has been reached, the maximum duration has been reached, or the
1313   * SLAMD server indicates that a stop has been requested.
1314   */

1315  public void runJob()
1316  {
1317    // Determine the range of time for which we should collect statistics.
1318
long currentTime = System.currentTimeMillis();
1319    boolean collectingStats = false;
1320    long startCollectingTime = currentTime + (1000 * warmUpTime);
1321    long stopCollectingTime = Long.MAX_VALUE;
1322    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1323    {
1324      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1325    }
1326
1327    // Set a variable that we can use to determine if the connection is alive or
1328
// not
1329
boolean connected = false;
1330
1331    // Set a variable that should be used to determine whether all the entries
1332
// have been added yet or not.
1333
boolean allAdded = false;
1334
1335    // Set a variable that can be used to determine how long we should sleep
1336
// between adds.
1337
long addStartTime = 0;
1338
1339    // Create a variable that we will use for the LDAP connection
1340
conn = new LDAPConnection();
1341
1342
1343    // Create a loop that will run until it needs to stop
1344
while ((! shouldStop()) && (! allAdded))
1345    {
1346      currentTime = System.currentTimeMillis();
1347      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1348          (currentTime < stopCollectingTime))
1349      {
1350        // Tell the stat trackers that they should start tracking now
1351
addCount.startTracker();
1352        addTime.startTracker();
1353        resultCodes.startTracker();
1354        collectingStats = true;
1355
1356        if (reportLatencyTracker)
1357        {
1358          latencyTime.startTracker();
1359          latencyCategories.startTracker();
1360          replicaThread.startChecking();
1361          masterThread.startChecking();
1362        }
1363      }
1364      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1365      {
1366        addCount.stopTracker();
1367        addTime.stopTracker();
1368        resultCodes.stopTracker();
1369
1370        if (reportLatencyTracker)
1371        {
1372          latencyTime.stopTracker();
1373          latencyCategories.stopTracker();
1374          replicaThread.stopAndWait();
1375          masterThread.stopAndWait();
1376        }
1377
1378        collectingStats = false;
1379      }
1380
1381      // If the connection is currently not connected, then establish it
1382
if (! connected)
1383      {
1384        try
1385        {
1386          conn.connect(3, masterHost, masterPort, bindDN, bindPassword);
1387          connected = true;
1388        }
1389        catch (LDAPException le)
1390        {
1391          logMessage("ERROR -- Could not connect to " + masterHost + ":" +
1392                           masterPort + " (" + le + ") -- aborting thread");
1393          if (collectingStats)
1394          {
1395            resultCodes.increment(String.valueOf(le.getLDAPResultCode()));
1396          }
1397          indicateStoppedDueToError();
1398          break;
1399        }
1400      }
1401
1402      LDAPConstraints constraints = conn.getConstraints();
1403      if (useProxyAuth)
1404      {
1405        LDAPProxiedAuthControl proxyAuthControl =
1406             new LDAPProxiedAuthControl(proxyAsDN, true);
1407        constraints.setServerControls(proxyAuthControl);
1408      }
1409      constraints.setTimeLimit(1000 * timeLimit);
1410
1411
1412      // Create a flag used to determine if the add was successful.
1413
LDAPEntry entryToAdd = createEntry();
1414      if (entryToAdd == null)
1415      {
1416        allAdded = true;
1417      }
1418      else
1419      {
1420        // Record the current time as the start of the add.
1421
if (collectingStats)
1422        {
1423          addTime.startTimer();
1424        }
1425        if (delay > 0)
1426        {
1427          addStartTime = System.currentTimeMillis();
1428        }
1429
1430        // Perform the add
1431
int resultCode = LDAPException.SUCCESS;
1432        try
1433        {
1434          conn.add(entryToAdd, constraints);
1435        }
1436        catch (LDAPException le)
1437        {
1438          resultCode = le.getLDAPResultCode();
1439        }
1440
1441
1442        // Record the current time as the end of the add.
1443
if (collectingStats)
1444        {
1445          addCount.increment();
1446          addTime.stopTimer();
1447          resultCodes.increment(String.valueOf(resultCode));
1448        }
1449      }
1450
1451      // If the connection should be broken, then do so
1452
if (alwaysDisconnect)
1453      {
1454        try
1455        {
1456          conn.disconnect();
1457        } catch (LDAPException le) {}
1458        connected = false;
1459      }
1460
1461      // If we need to sleep, then do so
1462
if ((delay > 0) && (! shouldStop()))
1463      {
1464        long now = System.currentTimeMillis();
1465        long sleepTime = delay - (now - addStartTime);
1466        if (sleepTime > 0)
1467        {
1468          try
1469          {
1470            Thread.sleep(sleepTime);
1471          } catch (InterruptedException JavaDoc ie) {}
1472        }
1473      }
1474    }
1475
1476
1477    // If the connection is still established, then close it
1478
try
1479    {
1480      conn.disconnect();
1481    } catch (LDAPException le) {}
1482
1483
1484    // Tell the stat trackers that they should stop tracking
1485
if (collectingStats)
1486    {
1487      addCount.stopTracker();
1488      addTime.stopTimer();
1489      resultCodes.stopTracker();
1490
1491      if (reportLatencyTracker)
1492      {
1493        latencyTime.stopTracker();
1494        latencyCategories.stopTracker();
1495        replicaThread.stopAndWait();
1496        masterThread.stopAndWait();
1497      }
1498    }
1499  }
1500
1501
1502
1503  /**
1504   * Attempts to force this thread to exit by closing the connection to the
1505   * directory server and setting it to <CODE>null</CODE>.
1506   */

1507  public void destroy()
1508  {
1509    if (conn != null)
1510    {
1511      try
1512      {
1513        conn.disconnect();
1514      } catch (Exception JavaDoc e) {}
1515
1516      conn = null;
1517    }
1518
1519    if (masterThread != null)
1520    {
1521      masterThread.masterThread.interrupt();
1522
1523      try
1524      {
1525        masterThread.connection.disconnect();
1526      } catch (Exception JavaDoc e) {}
1527
1528      masterThread.connection = null;
1529      masterThread = null;
1530    }
1531
1532    if (replicaThread != null)
1533    {
1534      replicaThread.replicaThread.interrupt();
1535
1536      try
1537      {
1538        replicaThread.connection.disconnect();
1539      } catch (Exception JavaDoc e) {}
1540
1541      replicaThread.connection = null;
1542      replicaThread = null;
1543    }
1544  }
1545
1546
1547
1548  /**
1549   * Ensures that the master and replica check threads are properly stopped.
1550   */

1551  public void finalizeClient()
1552  {
1553    masterThread.stopAndWait();
1554    replicaThread.stopAndWait();
1555  }
1556
1557
1558
1559  /**
1560   * Creates a randomly-generated LDAP entry to be added to the directory.
1561   *
1562   * @return The randomly-generated entry.
1563   */

1564  public LDAPEntry createEntry()
1565  {
1566    int nextRDNValue = nextValue++;
1567    if (nextRDNValue > maxRDNValue)
1568    {
1569      return null;
1570    }
1571
1572    LDAPAttribute[] attrs = new LDAPAttribute[attrsToInclude.length + 1];
1573    attrs[0] = new LDAPAttribute("objectClass", OBJECTCLASS_VALUES);
1574    for (int i=0; i < attrsToInclude.length; i++)
1575    {
1576      int colonPos;
1577      if (attrsToInclude[i].equals(rdnAttr))
1578      {
1579        attrs[i+1] = new LDAPAttribute(attrsToInclude[i],
1580                                       String.valueOf(nextRDNValue));
1581      }
1582      else if ((colonPos = attrsToInclude[i].indexOf(':')) > 0)
1583      {
1584        attrs[i+1] = new LDAPAttribute(attrsToInclude[i].substring(0, colonPos),
1585                              attrsToInclude[i].substring(colonPos+1).trim());
1586
1587      }
1588      else
1589      {
1590        attrs[i+1] = new LDAPAttribute(attrsToInclude[i],
1591                                       getRandomString(valueLength));
1592      }
1593    }
1594
1595    return new LDAPEntry(rdnAttr + "=" + nextRDNValue + "," + baseDN,
1596                         new LDAPAttributeSet(attrs));
1597  }
1598
1599
1600
1601  /**
1602   * Retrieves a string containing the specified number of randomly-chosen
1603   * characters.
1604   *
1605   * @param length The number of characters to include in the string.
1606   *
1607   * @return A string containing the specified number of randomly-chosen
1608   * characters.
1609   */

1610  public String JavaDoc getRandomString(int length)
1611  {
1612    char[] returnChars = new char[length];
1613
1614    for (int i=0; i < length; i++)
1615    {
1616      returnChars[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
1617                                ALPHABET.length];
1618    }
1619
1620    return new String JavaDoc(returnChars);
1621  }
1622}
1623
1624
Popular Tags