KickJava   Java API By Example, From Geeks To Geeks.

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


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

16 package com.sun.slamd.example;
17
18
19
20 import java.io.*;
21 import java.security.*;
22 import java.util.*;
23 import netscape.ldap.*;
24 import netscape.ldap.controls.*;
25 import netscape.ldap.factory.*;
26 import com.sun.slamd.job.*;
27 import com.sun.slamd.parameter.*;
28 import com.sun.slamd.stat.*;
29
30
31
32 /**
33  * This class implements a SLAMD job class for performing repeated add
34  * operations against an LDAP directory server. All of the configuration for
35  * this job thread can be provided through parameters.
36  *
37  *
38  * @author Neil A. Wilson
39  */

40 public class AddRateJobClass
41        extends JobClass
42 {
43   /**
44    * The system property used to specify the location of the JSSE key store.
45    */

46   public static final String JavaDoc SSL_KEY_STORE_PROPERTY =
47        "javax.net.ssl.keyStore";
48
49
50
51   /**
52    * The system property used to specify the password for the JSSE key store.
53    */

54   public static final String JavaDoc SSL_KEY_PASSWORD_PROPERTY =
55        "javax.net.ssl.keyStorePassword";
56
57
58
59   /**
60    * The system property used to specify the location of the JSSE trust store.
61    */

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

70   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
71        "javax.net.ssl.trustStorePassword";
72
73
74
75   /**
76    * The display name for the stat tracker that will be used to track the time
77    * required to perform each add.
78    */

79   public static final String JavaDoc STAT_TRACKER_ADD_TIME = "Add Time (ms)";
80
81
82
83   /**
84    * The display name for the stat tracker that will be used to track the number
85    * of adds performed.
86    */

87   public static final String JavaDoc STAT_TRACKER_ADD_COUNT = "Adds Performed";
88
89
90
91   /**
92    * The display name for the stat tracker that will be used to accumulate the
93    * number of adds performed.
94    */

95   public static final String JavaDoc STAT_TRACKER_TOTAL_COUNT = "Total Adds Performed";
96
97
98
99   /**
100    * The display name for the stat tracker that will be used to track the number
101    * of exceptions caught.
102    */

103   public static final String JavaDoc STAT_TRACKER_RESULT_CODES = "Result Codes";
104
105
106
107   /**
108    * The characters that are available for use in the randomly-generated values.
109    */

110   public static final char[] ALPHABET =
111        "abcdefghijklmnopqrstuvwxyz".toCharArray();
112
113
114   /**
115    * The default set of attributes to include in the entries that are generated.
116    */

117   public static final String JavaDoc[] DEFAULT_ATTR_NAMES = new String JavaDoc[]
118   {
119     "givenname",
120     "sn",
121     "cn",
122     "uid",
123     "userpassword",
124     "mail",
125   };
126
127
128
129   /**
130    * The default set of objectclass values to create.
131    */

132   public static final String JavaDoc[] OBJECTCLASS_VALUES = new String JavaDoc[]
133   {
134     "top",
135     "person",
136     "organizationalPerson",
137     "inetOrgPerson",
138     "extensibleObject"
139   };
140
141
142
143   // The parameter that indicates whether the client should trust any SSL cert.
144
BooleanParameter blindTrustParameter =
145     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
146                          "Indicates whether the client should blindly trust " +
147                          "any certificate presented by the server, or " +
148                          "whether the key and trust stores should be used.",
149                          true);
150
151   // The parameter that indicates whether to disconnect after each add
152
BooleanParameter disconnectParameter =
153        new BooleanParameter("disconnect", "Always Disconnect",
154                             "Indicates whether to close the connection after " +
155                             "each add", false);
156
157   // The parameter that indicates whether the connection should use SSL
158
BooleanParameter useSSLParameter =
159     new BooleanParameter("usessl", "Use SSL",
160                          "Indicates whether SSL should be used for all " +
161                          "communication with the directory server", false);
162
163   // The parmeter that specifies the cool-down time in seconds.
164
IntegerParameter coolDownParameter =
165        new IntegerParameter("cool_down", "Cool Down Time",
166                             "The time in seconds that the job should " +
167                             "continue adding after ending statistics " +
168                             "collection.", true, 0, true, 0, false, 0);
169
170   // The parameter that indicates the delay that should be used between each
171
// request sent by a thread.
172
IntegerParameter delayParameter =
173        new IntegerParameter("delay", "Time Between Requests (ms)",
174                             "Specifies the length of time in milliseconds " +
175                             "each thread should wait between add " +
176                             "requests. Note that this delay will be " +
177                             "between consecutive requests and not between " +
178                             "the response of one operation and the request " +
179                             "for the next. If an add takes longer than " +
180                             "this length of time, then there will be no delay.",
181                             true, 0, true, 0, false, 0);
182
183   // The parameter that indicates the length of the generated attribute values.
184
IntegerParameter lengthParameter =
185     new IntegerParameter("value_length", "Generated Value Length",
186                          "Specifies the number of characters that should be " +
187                          "included in the generated values of the attriubtes.",
188                          true, 80, true, 1, false, 0);
189
190   // The parameter that indicates the port number for the directory server
191
IntegerParameter portParameter =
192        new IntegerParameter("ldapport", "Directory Server Port",
193                             "The port number for the LDAP directory server",
194                             true, 389, true, 1, true, 65535);
195
196   // The parameter that specifies the starting number for the RDN values.
197
IntegerParameter rdnStartParameter =
198        new IntegerParameter("rdn_start", "Initial RDN Value Number",
199                             "The number to use as the value of the RDN " +
200                             "attribute for the first entry to create", true, 1,
201                             false, 0, false, 0);
202
203   // The parameter that specifies the ending number for the RDN values.
204
IntegerParameter rdnEndParameter =
205        new IntegerParameter("rdn_end", "Final RDN Value Number",
206                             "The number to use as the value of the RDN " +
207                             "attribute for the last entry to create", false, 0,
208                             false, 0, false, 0);
209
210   // The parameter that indicates the maximum time limit for add operations.
211
IntegerParameter timeLimitParameter =
212        new IntegerParameter("time_limit", "Add Time Limit",
213                             "The maximum length of time in seconds that the " +
214                             "thread should wait for a add operation to be " +
215                             "performed before cancelling it and trying " +
216                             "another.", false, 0, true, 0, false, 0);
217
218   // The parmeter that specifies the cool-down time in seconds.
219
IntegerParameter warmUpParameter =
220        new IntegerParameter("warm_up", "Warm Up Time",
221                             "The time in seconds that the job should " +
222                             "add before beginning statistics collection.",
223                             true, 0, true, 0, false, 0);
224
225   // The names of additional attributes to add to the entries that are created.
226
MultiLineTextParameter extraAttrsParameter =
227        new MultiLineTextParameter("extra_attrs", "Additional Attributes",
228                                   "The names of additional attributes to " +
229                                   "include in the entries that will be " +
230                                   "generated. By default, inetOrgPerson " +
231                                   "entries will be created, with attributes " +
232                                   "of givenName, sn, cn, uid, userPassword, " +
233                                   "and mail, but they will also include the " +
234                                   "extensibleObject objectclass so that any " +
235                                   "additional attributes may be used. Each " +
236                                   "attribute specified will be given a " +
237                                   "value of a string of 80 randomly-chosen " +
238                                   "characters.", null, false);
239
240   // The placeholder parameter used as a spacer in the admin interface.
241
PlaceholderParameter placeholder = new PlaceholderParameter();
242
243   // The parameter that indicates the DN to use when binding to the server
244
StringParameter bindDNParameter =
245        new StringParameter("binddn", "Bind DN",
246                            "The DN to use to bind to the server", false, "");
247
248   // The parameter that indicates the base below which entries will be added.
249
StringParameter baseDNParameter =
250        new StringParameter("basedn", "Base DN ",
251                            "The base below which to add the entries",
252                            true, "");
253
254   // The parameter that indicates the address of the directory server
255
StringParameter hostParameter =
256        new StringParameter("ldaphost", "Directory Server Host",
257                            "The DNS hostname or IP address of the LDAP " +
258                            "directory server", 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 specifies the location of the SSL key store
274
StringParameter keyStoreParameter =
275     new StringParameter("sslkeystore", "SSL Key Store",
276                         "The path to the JSSE key store to use for an " +
277                         "SSL-based connection", false, "");
278
279   // The parameter that specifies the location of the SSL trust store
280
StringParameter trustStoreParameter =
281     new StringParameter("ssltruststore", "SSL Trust Store",
282                         "The path to the JSSE trust store to use for an " +
283                         "SSL-based connection", false, "");
284
285   // The parameter that indicates the bind password
286
PasswordParameter bindPWParameter =
287        new PasswordParameter("bindpw", "Bind Password",
288                              "The password for the bind DN", false, "");
289
290   // The parameter that specifies the password for the SSL key store
291
PasswordParameter keyPWParameter =
292     new PasswordParameter("sslkeypw", "SSL Key Store Password",
293                           "The password for the JSSE key store", false, "");
294
295   // The parameter that specifies the password for the SSL key store
296
PasswordParameter trustPWParameter =
297     new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
298                           "The password for the JSSE trust store", false, "");
299
300
301   // Instance variables that correspond to the parameter values
302
static boolean alwaysDisconnect;
303   static boolean blindTrust;
304   static boolean useProxyAuth;
305   static boolean useSSL;
306   static int coolDownTime;
307   static int maxRDNValue;
308   static int minRDNValue;
309   static int ldapPort;
310   static int nextValue;
311   static int timeLimit;
312   static int valueLength;
313   static int warmUpTime;
314   static long delay;
315   static String JavaDoc baseDN;
316   static String JavaDoc bindDN;
317   static String JavaDoc bindPassword;
318   static String JavaDoc ldapHost;
319   static String JavaDoc proxyAsDN;
320   static String JavaDoc rdnAttr;
321   static String JavaDoc sslKeyStore;
322   static String JavaDoc sslKeyPassword;
323   static String JavaDoc sslTrustStore;
324   static String JavaDoc sslTrustPassword;
325   static String JavaDoc[] attrsToInclude;
326
327
328   // The connection to the directory server over which the adds will be
329
// performed.
330
LDAPConnection conn;
331
332
333   // Variables used for status counters
334
AccumulatingTracker totalAdds;
335   CategoricalTracker resultCodes;
336   IncrementalTracker addCount;
337   TimeTracker addTime;
338
339
340   // One random number generator for use throughout the client and another to
341
// use for only the current thread.
342
static Random parentRandom;
343   Random random;
344
345
346
347
348   /**
349    * The default constructor used to create a new instance of the add thread.
350    * The only thing it should do is to invoke the superclass constructor. All
351    * other initialization should be performed in the <CODE>initialize</CODE>
352    * method.
353    */

354   public AddRateJobClass()
355   {
356     super();
357   }
358
359
360
361   /**
362    * Retrieves the name of the job performed by this job thread.
363    *
364    * @return The name of the job performed by this job thread.
365    */

366   public String JavaDoc getJobName()
367   {
368     return "LDAP AddRate";
369   }
370
371
372
373   /**
374    * Retrieves a description of the job performed by this job thread.
375    *
376    * @return A description of the job performed by this job thread.
377    */

378   public String JavaDoc getJobDescription()
379   {
380     return "This job can be used to perform repeated add operations against " +
381            "an LDAP directory server to generate load and measure performance";
382   }
383
384
385
386   /**
387    * Retrieves the name of the category in which this job class exists. This is
388    * used to help arrange the job classes in the administrative interface.
389    *
390    * @return The name of the category in which this job class exists.
391    */

392   public String JavaDoc getJobCategoryName()
393   {
394     return "LDAP";
395   }
396
397
398
399   /**
400    * Overrides the number of clients that may be used for this job to ensure
401    * that only a single client will be used.
402    *
403    * @return The number of clients that will always be used for this job.
404    */

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

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

479   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
480                                            int collectionInterval)
481   {
482     return new StatTracker[]
483     {
484       new IncrementalTracker(clientID, threadID, STAT_TRACKER_ADD_COUNT,
485                              collectionInterval),
486       new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
487                       collectionInterval),
488       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
489                              collectionInterval)
490     };
491   }
492
493
494
495   /**
496    * Retrieves the stat trackers that are maintained for this job thread.
497    *
498    * @return The stat trackers that are maintained for this job thread.
499    */

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

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

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

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

911   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
912          throws UnableToRunException
913   {
914     // Get the address of the target directory server
915
ldapHost = null;
916     hostParameter = parameters.getStringParameter(hostParameter.getName());
917     if (hostParameter != null)
918     {
919       ldapHost = hostParameter.getStringValue();
920     }
921
922     // Get the port for the target directory server
923
ldapPort = 389;
924     portParameter = parameters.getIntegerParameter(portParameter.getName());
925     if (portParameter != null)
926     {
927       ldapPort = portParameter.getIntValue();
928     }
929
930     // Get the bind DN for the target directory server
931
bindDN = "";
932     bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
933     if (bindDNParameter != null)
934     {
935       bindDN = bindDNParameter.getStringValue();
936     }
937
938     // Get the bind password for the target directory server
939
bindPassword = "";
940     bindPWParameter =
941          parameters.getPasswordParameter(bindPWParameter.getName());
942     if (bindPWParameter != null)
943     {
944       bindPassword = bindPWParameter.getStringValue();
945     }
946
947     // Get the DN of the proxy as user.
948
useProxyAuth = false;
949     proxyAsDNParameter =
950          parameters.getStringParameter(proxyAsDNParameter.getName());
951     if ((proxyAsDNParameter != null) && (proxyAsDNParameter.hasValue()))
952     {
953       useProxyAuth = true;
954       proxyAsDN = proxyAsDNParameter.getStringValue();
955     }
956
957     // Get the base DN under which to add the entries.
958
baseDN = null;
959     baseDNParameter = parameters.getStringParameter(baseDNParameter.getName());
960     if ((baseDNParameter != null) && (baseDNParameter.hasValue()))
961     {
962       baseDN = baseDNParameter.getStringValue();
963     }
964
965     // Get the name of the RDN attribute to use.
966
rdnAttr = "uid";
967     rdnAttrParameter =
968          parameters.getStringParameter(rdnAttrParameter.getName());
969     if ((rdnAttrParameter != null) && (rdnAttrParameter.hasValue()))
970     {
971       rdnAttr = rdnAttrParameter.getStringValue().toLowerCase();
972     }
973
974     // Get the initial RDN value to create.
975
minRDNValue = 0;
976     rdnStartParameter =
977          parameters.getIntegerParameter(rdnStartParameter.getName());
978     if ((rdnStartParameter != null) && (rdnStartParameter.hasValue()))
979     {
980       minRDNValue = rdnStartParameter.getIntValue();
981     }
982     nextValue = minRDNValue;
983
984     // Get the final RDN value to create.
985
maxRDNValue = Integer.MAX_VALUE;
986     rdnEndParameter = parameters.getIntegerParameter(rdnEndParameter.getName());
987     if ((rdnEndParameter != null) && (rdnEndParameter.hasValue()))
988     {
989       maxRDNValue = rdnEndParameter.getIntValue();
990       if (maxRDNValue <= 0)
991       {
992         maxRDNValue = Integer.MAX_VALUE;
993       }
994     }
995
996     // Get the length to use for the attribute values.
997
valueLength = 80;
998     lengthParameter = parameters.getIntegerParameter(lengthParameter.getName());
999     if ((lengthParameter != null) && (lengthParameter.hasValue()))
1000    {
1001      valueLength = lengthParameter.getIntValue();
1002    }
1003
1004    // Get the extra attributes to include in the entry.
1005
attrsToInclude = DEFAULT_ATTR_NAMES;
1006    extraAttrsParameter =
1007         parameters.getMultiLineTextParameter(extraAttrsParameter.getName());
1008    if ((extraAttrsParameter != null) && (extraAttrsParameter.hasValue()))
1009    {
1010      String JavaDoc[] extraAttrs = extraAttrsParameter.getNonBlankLines();
1011      String JavaDoc[] tmpAttrs = new String JavaDoc[attrsToInclude.length + extraAttrs.length];
1012      System.arraycopy(attrsToInclude, 0, tmpAttrs, 0, attrsToInclude.length);
1013      for (int i=attrsToInclude.length, j=0; i < tmpAttrs.length; i++,j++)
1014      {
1015        tmpAttrs[i] = extraAttrs[j].toLowerCase();
1016      }
1017
1018      attrsToInclude = tmpAttrs;
1019    }
1020
1021    // Get the warm up time.
1022
warmUpTime = 0;
1023    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1024    if (warmUpParameter != null)
1025    {
1026      warmUpTime = warmUpParameter.getIntValue();
1027    }
1028
1029    // Get the cool down time.
1030
coolDownTime = 0;
1031    coolDownParameter =
1032         parameters.getIntegerParameter(coolDownParameter.getName());
1033    if (coolDownParameter != null)
1034    {
1035      coolDownTime = coolDownParameter.getIntValue();
1036    }
1037
1038    // Get the maximum add time limit.
1039
timeLimit = 0;
1040    timeLimitParameter =
1041         parameters.getIntegerParameter(timeLimitParameter.getName());
1042    if (timeLimitParameter != null)
1043    {
1044      timeLimit = timeLimitParameter.getIntValue();
1045    }
1046
1047    // Get the delay between requests.
1048
delay = 0;
1049    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1050    if (delayParameter != null)
1051    {
1052      delay = delayParameter.getIntValue();
1053    }
1054
1055    // Get the flag indicating whether we should use SSL or not
1056
useSSL = false;
1057    useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
1058    if (useSSLParameter != null)
1059    {
1060      useSSL = useSSLParameter.getBooleanValue();
1061    }
1062
1063    // If we are to use SSL, then get all the other SSL-related info
1064
if (useSSL)
1065    {
1066      blindTrustParameter =
1067           parameters.getBooleanParameter(blindTrustParameter.getName());
1068      if (blindTrustParameter != null)
1069      {
1070        blindTrust = blindTrustParameter.getBooleanValue();
1071      }
1072
1073      // The location of the JSSE key store
1074
sslKeyStore = null;
1075      keyStoreParameter =
1076           parameters.getStringParameter(keyStoreParameter.getName());
1077      if ((keyStoreParameter != null) && (keyStoreParameter.hasValue()))
1078      {
1079        sslKeyStore = keyStoreParameter.getStringValue();
1080        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1081      }
1082
1083      // The JSSE key store password
1084
sslKeyPassword = null;
1085      keyPWParameter =
1086           parameters.getPasswordParameter(keyPWParameter.getName());
1087      if ((keyPWParameter != null) && (keyPWParameter.hasValue()))
1088      {
1089        sslKeyPassword = keyPWParameter.getStringValue();
1090        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPassword);
1091      }
1092
1093      // The location of the JSSE trust store
1094
sslTrustStore = null;
1095      trustStoreParameter =
1096           parameters.getStringParameter(trustStoreParameter.getName());
1097      if ((trustStoreParameter != null) && (trustStoreParameter.hasValue()))
1098      {
1099        sslTrustStore = trustStoreParameter.getStringValue();
1100        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1101      }
1102
1103      // The JSSE trust store password
1104
sslTrustPassword = null;
1105      trustPWParameter =
1106           parameters.getPasswordParameter(trustPWParameter.getName());
1107      if ((trustPWParameter != null) && (trustPWParameter.hasValue()))
1108      {
1109        sslTrustPassword = trustPWParameter.getStringValue();
1110        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPassword);
1111      }
1112    }
1113
1114    // Get the flag indicating whether we should disconnect after each add.
1115
alwaysDisconnect = false;
1116    disconnectParameter =
1117         parameters.getBooleanParameter(disconnectParameter.getName());
1118    if (disconnectParameter != null)
1119    {
1120      alwaysDisconnect = disconnectParameter.getBooleanValue();
1121    }
1122
1123
1124    // Initialize the parent random number generator
1125
parentRandom = new Random();
1126  }
1127
1128
1129
1130  /**
1131   * Initializes this job thread to be used to actually run the job on the
1132   * client. The provided parameter list should be processed to customize the
1133   * behavior of this job thread, and any other initialization that needs to be
1134   * done in order for the job to run should be performed here as well.
1135   *
1136   * @param clientID The client ID for this job thread.
1137   * @param threadID The thread ID for this job thread.
1138   * @param collectionInterval The length of time in seconds to use as the
1139   * statistics collection interval.
1140   * @param parameters The set of parameters provided to this job that
1141   * can be used to customize its behavior.
1142   *
1143   * @throws UnableToRunException If a problem occurs while initializing the
1144   * job thread.
1145   */

1146  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1147                               int collectionInterval, ParameterList parameters)
1148         throws UnableToRunException
1149  {
1150    // Set up the stat trackers
1151
addCount = new IncrementalTracker(clientID, threadID,
1152                                      STAT_TRACKER_ADD_COUNT,
1153                                      collectionInterval);
1154    totalAdds = new AccumulatingTracker(clientID, threadID,
1155                                        STAT_TRACKER_TOTAL_COUNT,
1156                                        collectionInterval);
1157    addTime = new TimeTracker(clientID, threadID, STAT_TRACKER_ADD_TIME,
1158                              collectionInterval);
1159    resultCodes = new CategoricalTracker(clientID, threadID,
1160                                         STAT_TRACKER_RESULT_CODES,
1161                                         collectionInterval);
1162
1163
1164    // Enable real-time reporting of the data for these stat trackers.
1165
RealTimeStatReporter statReporter = getStatReporter();
1166    if (statReporter != null)
1167    {
1168      String JavaDoc jobID = getJobID();
1169      addCount.enableRealTimeStats(statReporter, jobID);
1170      totalAdds.enableRealTimeStats(statReporter, jobID);
1171      addTime.enableRealTimeStats(statReporter, jobID);
1172    }
1173
1174
1175    // Initialize the random number generator for this thread.
1176
random = new Random(parentRandom.nextLong());
1177
1178
1179    // If the connection is to use SSL, then establish a preliminary connection
1180
// now. The first connection can take a significant amount of time to
1181
// establish, and we want to get it out of the way early before the timer
1182
// starts (if a duration is specified). Don't worry about any exceptions
1183
// that may get thrown here because there's no easy way to report them back
1184
// but they will be repeated and handled when the job starts running anyway,
1185
// so no big deal.
1186
if (useSSL)
1187    {
1188      try
1189      {
1190        if (blindTrust)
1191        {
1192          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1193        }
1194        else
1195        {
1196          conn = new LDAPConnection(new JSSESocketFactory(null));
1197        }
1198        conn.connect(3, ldapHost, ldapPort, bindDN, bindPassword);
1199        conn.disconnect();
1200      }
1201      catch (Exception JavaDoc e) {}
1202    }
1203  }
1204
1205
1206
1207  /**
1208   * Perform the work of this job thread by establishing the connection(s) to
1209   * the directory server and issuing all the appropriate queries. The job will
1210   * continue until the specified number of iterations have been performed, the
1211   * stop time has been reached, the maximum duration has been reached, or the
1212   * SLAMD server indicates that a stop has been requested.
1213   */

1214  public void runJob()
1215  {
1216    // Determine the range of time for which we should collect statistics.
1217
long currentTime = System.currentTimeMillis();
1218    boolean collectingStats = false;
1219    long startCollectingTime = currentTime + (1000 * warmUpTime);
1220    long stopCollectingTime = Long.MAX_VALUE;
1221    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1222    {
1223      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1224    }
1225
1226    // Set a variable that we can use to determine if the connection is alive or
1227
// not
1228
boolean connected = false;
1229
1230    // Set a variable that should be used to determine whether all the entries
1231
// have been added yet or not.
1232
boolean allAdded = false;
1233
1234    // Set a variable that can be used to determine how long we should sleep
1235
// between adds.
1236
long addStartTime = 0;
1237
1238    // Create a variable that we will use for the LDAP connection
1239
if (useSSL)
1240    {
1241      if (blindTrust)
1242      {
1243        try
1244        {
1245          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1246        }
1247        catch (LDAPException le)
1248        {
1249          logMessage(le.getMessage());
1250          indicateStoppedDueToError();
1251          return;
1252        }
1253      }
1254      else
1255      {
1256        conn = new LDAPConnection(new JSSESocketFactory(null));
1257      }
1258    }
1259    else
1260    {
1261      conn = new LDAPConnection();
1262    }
1263
1264
1265    // Create a loop that will run until it needs to stop
1266
while ((! shouldStop()) && (! allAdded))
1267    {
1268      currentTime = System.currentTimeMillis();
1269      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1270          (currentTime < stopCollectingTime))
1271      {
1272        // Tell the stat trackers that they should start tracking now
1273
addCount.startTracker();
1274        totalAdds.startTracker();
1275        addTime.startTracker();
1276        resultCodes.startTracker();
1277        collectingStats = true;
1278      }
1279      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1280      {
1281        addCount.stopTracker();
1282        totalAdds.stopTracker();
1283        addTime.stopTracker();
1284        resultCodes.stopTracker();
1285        collectingStats = false;
1286      }
1287
1288      // If the connection is currently not connected, then establish it
1289
if (! connected)
1290      {
1291        try
1292        {
1293          conn.connect(3, ldapHost, ldapPort, bindDN, bindPassword);
1294          connected = true;
1295        }
1296        catch (LDAPException le)
1297        {
1298          logMessage("ERROR -- Could not connect to " + ldapHost + ":" +
1299                           ldapPort + " (" + le + ") -- aborting thread");
1300          if (collectingStats)
1301          {
1302            resultCodes.increment(String.valueOf(le.getLDAPResultCode()));
1303          }
1304          indicateStoppedDueToError();
1305          break;
1306        }
1307      }
1308
1309      LDAPConstraints constraints = conn.getConstraints();
1310      if (useProxyAuth)
1311      {
1312        LDAPProxiedAuthControl proxyAuthControl =
1313             new LDAPProxiedAuthControl(proxyAsDN, true);
1314        constraints.setServerControls(proxyAuthControl);
1315      }
1316      constraints.setTimeLimit(1000 * timeLimit);
1317
1318
1319      // Create a flag used to determine if the add was successful.
1320
LDAPEntry entryToAdd = createEntry();
1321      if (entryToAdd == null)
1322      {
1323        allAdded = true;
1324      }
1325      else
1326      {
1327        // Record the current time as the start of the add.
1328
if (collectingStats)
1329        {
1330          addTime.startTimer();
1331        }
1332        if (delay > 0)
1333        {
1334          addStartTime = System.currentTimeMillis();
1335        }
1336
1337        // Perform the add
1338
int resultCode = LDAPException.SUCCESS;
1339        try
1340        {
1341          conn.add(entryToAdd, constraints);
1342        }
1343        catch (LDAPException le)
1344        {
1345          resultCode = le.getLDAPResultCode();
1346        }
1347
1348
1349        // Record the current time as the end of the add.
1350
if (collectingStats)
1351        {
1352          addCount.increment();
1353          totalAdds.increment();
1354          addTime.stopTimer();
1355          resultCodes.increment(String.valueOf(resultCode));
1356        }
1357      }
1358
1359      // If the connection should be broken, then do so
1360
if (alwaysDisconnect)
1361      {
1362        try
1363        {
1364          conn.disconnect();
1365        } catch (LDAPException le) {}
1366        connected = false;
1367      }
1368
1369      // If we need to sleep, then do so
1370
if ((delay > 0) && (! shouldStop()))
1371      {
1372        long now = System.currentTimeMillis();
1373        long sleepTime = delay - (now - addStartTime);
1374        if (sleepTime > 0)
1375        {
1376          try
1377          {
1378            Thread.sleep(sleepTime);
1379          } catch (InterruptedException JavaDoc ie) {}
1380        }
1381      }
1382    }
1383
1384
1385    // If the connection is still established, then close it
1386
try
1387    {
1388      conn.disconnect();
1389    } catch (LDAPException le) {}
1390
1391
1392    // Tell the stat trackers that they should stop tracking
1393
if (collectingStats)
1394    {
1395      addCount.stopTracker();
1396      totalAdds.stopTracker();
1397      addTime.stopTimer();
1398      resultCodes.stopTracker();
1399    }
1400  }
1401
1402
1403
1404  /**
1405   * Attempts to force this thread to exit by closing the connection to the
1406   * directory server and setting it to <CODE>null</CODE>.
1407   */

1408  public void destroy()
1409  {
1410    if (conn != null)
1411    {
1412      try
1413      {
1414        conn.disconnect();
1415      } catch (Exception JavaDoc e) {}
1416
1417      conn = null;
1418    }
1419  }
1420
1421
1422
1423  /**
1424   * Creates a randomly-generated LDAP entry to be added to the directory.
1425   *
1426   * @return The randomly-generated entry.
1427   */

1428  public LDAPEntry createEntry()
1429  {
1430    int nextRDNValue = nextValue++;
1431    if (nextRDNValue > maxRDNValue)
1432    {
1433      return null;
1434    }
1435
1436    LDAPAttribute[] attrs = new LDAPAttribute[attrsToInclude.length + 1];
1437    attrs[0] = new LDAPAttribute("objectClass", OBJECTCLASS_VALUES);
1438    for (int i=0; i < attrsToInclude.length; i++)
1439    {
1440      int colonPos;
1441      if (attrsToInclude[i].equals(rdnAttr))
1442      {
1443        attrs[i+1] = new LDAPAttribute(attrsToInclude[i],
1444                                       String.valueOf(nextRDNValue));
1445      }
1446      else if ((colonPos = attrsToInclude[i].indexOf(':')) > 0)
1447      {
1448        attrs[i+1] = new LDAPAttribute(attrsToInclude[i].substring(0, colonPos),
1449                              attrsToInclude[i].substring(colonPos+1).trim());
1450
1451      }
1452      else
1453      {
1454        attrs[i+1] = new LDAPAttribute(attrsToInclude[i],
1455                                       getRandomString(valueLength));
1456      }
1457    }
1458
1459    return new LDAPEntry(rdnAttr + "=" + nextRDNValue + "," + baseDN,
1460                         new LDAPAttributeSet(attrs));
1461  }
1462
1463
1464
1465  /**
1466   * Retrieves a string containing the specified number of randomly-chosen
1467   * characters.
1468   *
1469   * @param length The number of characters to include in the string.
1470   *
1471   * @return A string containing the specified number of randomly-chosen
1472   * characters.
1473   */

1474  public String JavaDoc getRandomString(int length)
1475  {
1476    char[] returnChars = new char[length];
1477
1478    for (int i=0; i < length; i++)
1479    {
1480      returnChars[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
1481                                ALPHABET.length];
1482    }
1483
1484    return new String JavaDoc(returnChars);
1485  }
1486}
1487
1488
Popular Tags