KickJava   Java API By Example, From Geeks To Geeks.

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


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

40 public class CompRateJobClass
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 compare.
78    */

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

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

95   public static final String JavaDoc STAT_TRACKER_EXCEPTIONS_CAUGHT =
96        "Exceptions Caught";
97
98
99
100   /**
101    * The characters that are available for use in the randomly-generated values.
102    */

103   public static final char[] ALPHABET =
104        "abcdefghijklmnopqrstuvwxyz".toCharArray();
105
106
107
108
109
110   // The parameter that indicates whether the client should trust any SSL cert.
111
BooleanParameter blindTrustParameter =
112     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
113                          "Indicates whether the client should blindly trust " +
114                          "any certificate presented by the server, or " +
115                          "whether the key and trust stores should be used.",
116                          true);
117
118   // The parameter that indicates whether to disconnect after each compare
119
BooleanParameter disconnectParameter =
120        new BooleanParameter("disconnect", "Always Disconnect",
121                             "Indicates whether to close the connection after " +
122                             "each compare", false);
123
124   // The parameter that indicates whether the connection should use SSL
125
BooleanParameter useSSLParameter =
126     new BooleanParameter("usessl", "Use SSL",
127                          "Indicates whether SSL should be used for all " +
128                          "communication with the directory server", false);
129
130   // The parameter that specifies a file containing entry DNs.
131
FileURLParameter dnURLParameter =
132        new FileURLParameter("dn_url", "DN File URL",
133                             "The URL (FILE or HTTP) that specifies the " +
134                             "DNs of the entries that may be compared.", null,
135                             false);
136
137   // The parmeter that specifies the cool-down time in seconds.
138
IntegerParameter coolDownParameter =
139        new IntegerParameter("cool_down", "Cool Down Time",
140                             "The time in seconds that the job should " +
141                             "continue comparing after ending statistics " +
142                             "collection.", true, 0, true, 0, false, 0);
143
144   // The parameter that indicates the delay that should be used between each
145
// request sent by a thread.
146
IntegerParameter delayParameter =
147        new IntegerParameter("delay", "Time Between Requests (ms)",
148                             "Specifies the length of time in milliseconds " +
149                             "each thread should wait between compare " +
150                             "requests. Note that this delay will be " +
151                             "between consecutive requests and not between " +
152                             "the response of one operation and the request " +
153                             "for the next. If a compare takes longer than " +
154                             "this length of time, then there will be no delay.",
155                             true, 0, true, 0, false, 0);
156
157   // The parameter that indicates the number of times the compare should be
158
// performed
159
IntegerParameter iterationsParameter =
160     new IntegerParameter("iterations", "Number of Iterations",
161                          "The number of compares that should be performed by " +
162                          "each thread", false, -1);
163
164   // The parameter that indicates the port number for the directory server
165
IntegerParameter portParameter =
166        new IntegerParameter("ldapport", "Directory Server Port",
167                             "The port number for the LDAP directory server",
168                             true, 389, true, 1, true, 65535);
169
170   // The parmeter that specifies the cool-down time in seconds.
171
IntegerParameter warmUpParameter =
172        new IntegerParameter("warm_up", "Warm Up Time",
173                             "The time in seconds that the job should " +
174                             "compare before beginning statistics collection.",
175                             true, 0, true, 0, false, 0);
176
177   // The placeholder parameter used as a spacer in the admin interface.
178
PlaceholderParameter placeholder = new PlaceholderParameter();
179
180   // The parameter that specifies the attribute to compare
181
StringParameter attributeParameter =
182        new StringParameter("attribute", "Attribute to Compare",
183                            "The attribute to compare in the entry", true,
184                            "description");
185
186   // The parameter that indicates the DN to use when binding to the server
187
StringParameter bindDNParameter =
188        new StringParameter("binddn", "Bind DN",
189                            "The DN to use to bind to the server", false, "");
190
191   // The parameter that indicates the DN of the entry to compare
192
StringParameter entryDNParameter =
193        new StringParameter("entrydn", "Entry DN",
194                            "The DN of the entry to compare", false, "");
195
196   // The parameter that indicates the address of the directory server
197
StringParameter hostParameter =
198        new StringParameter("ldaphost", "Directory Server Host",
199                            "The DNS hostname or IP address of the LDAP " +
200                            "directory server", true, "");
201
202   // The parameter that indicates the DN to use to proxy the comparisons
203
StringParameter proxyAsDNParameter =
204        new StringParameter("proxy_as_dn", "Proxy As DN",
205                            "The DN of the user whose credentials should be " +
206                            "used to perform the compare through the use " +
207                            "of the proxied authorization control.", false, "");
208
209   // The parameter that specifies the location of the SSL key store
210
StringParameter keyStoreParameter =
211     new StringParameter("sslkeystore", "SSL Key Store",
212                         "The path to the JSSE key store to use for an " +
213                         "SSL-based connection", false, "");
214
215   // The parameter that specifies the location of the SSL trust store
216
StringParameter trustStoreParameter =
217     new StringParameter("ssltruststore", "SSL Trust Store",
218                         "The path to the JSSE trust store to use for an " +
219                         "SSL-based connection", false, "");
220
221   // The parameter that indicates the bind password
222
PasswordParameter bindPWParameter =
223        new PasswordParameter("bindpw", "Bind Password",
224                              "The password for the bind DN", false, "");
225
226   // The parameter that specifies the password for the SSL key store
227
PasswordParameter keyPWParameter =
228     new PasswordParameter("sslkeypw", "SSL Key Store Password",
229                           "The password for the JSSE key store", false, "");
230
231   // The parameter that specifies the password for the SSL key store
232
PasswordParameter trustPWParameter =
233     new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
234                           "The password for the JSSE trust store", false, "");
235
236
237   // Instance variables that correspond to the parameter values
238
static boolean alwaysDisconnect;
239   static boolean blindTrust;
240   static boolean useDNFile;
241   static boolean useDNRange;
242   static boolean useProxyAuth;
243   static boolean useSequential;
244   static boolean useSSL;
245   static int coolDownTime;
246   static int dnRangeMax;
247   static int dnRangeMin;
248   static int dnRangeSpan;
249   static int iterations;
250   static int ldapPort;
251   static int sequentialCounter;
252   static int warmUpTime;
253   static long delay;
254   static String JavaDoc attribute;
255   static String JavaDoc bindDN;
256   static String JavaDoc bindPassword;
257   static String JavaDoc dnInitial;
258   static String JavaDoc dnFinal;
259   static String JavaDoc ldapHost;
260   static String JavaDoc proxyAsDN;
261   static String JavaDoc sslKeyStore;
262   static String JavaDoc sslKeyPassword;
263   static String JavaDoc sslTrustStore;
264   static String JavaDoc sslTrustPassword;
265   static String JavaDoc[] compDNs;
266
267
268   // The connection to the directory server to use to perform the compares.
269
LDAPConnection conn;
270
271
272   // Variables used for status counters
273
IncrementalTracker exceptionsCaught;
274   IncrementalTracker compCount;
275   TimeTracker compTime;
276
277
278   // One random number generator for use throughout the client and another to
279
// use for only the current thread.
280
static Random parentRandom;
281   Random random;
282
283
284
285
286   /**
287    * The default constructor used to create a new instance of the compare
288    * thread. The only thing it should do is to invoke the superclass
289    * constructor. All other initialization should be performed in the
290    * <CODE>initialize</CODE> method.
291    */

292   public CompRateJobClass()
293   {
294     super();
295   }
296
297
298
299   /**
300    * Retrieves the name of the job performed by this job thread.
301    *
302    * @return The name of the job performed by this job thread.
303    */

304   public String JavaDoc getJobName()
305   {
306     return "LDAP CompRate";
307   }
308
309
310
311   /**
312    * Retrieves a description of the job performed by this job thread.
313    *
314    * @return A description of the job performed by this job thread.
315    */

316   public String JavaDoc getJobDescription()
317   {
318     return "This job can be used to perform repeated compares against " +
319            "an LDAP directory server to generate load and measure performance";
320   }
321
322
323
324   /**
325    * Retrieves the name of the category in which this job class exists. This is
326    * used to help arrange the job classes in the administrative interface.
327    *
328    * @return The name of the category in which this job class exists.
329    */

330   public String JavaDoc getJobCategoryName()
331   {
332     return "LDAP";
333   }
334
335
336
337   /**
338    * Retrieve a parameter list that can be used to determine all of the
339    * customizeable options that are available for this job.
340    *
341    * @return A parameter list that can be used to determine all of the
342    * customizeable options that are available for this job.
343    */

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

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

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

456   public void validateJobInfo(int numClients, int threadsPerClient,
457                               int threadStartupDelay, Date startTime,
458                               Date stopTime, int duration,
459                               int collectionInterval, ParameterList parameters)
460          throws InvalidValueException
461   {
462     StringParameter dnParameter =
463          parameters.getStringParameter(entryDNParameter.getName());
464     FileURLParameter dnFileParameter =
465          parameters.getFileURLParameter(dnURLParameter.getName());
466     if (((dnParameter == null) || (! dnParameter.hasValue())) &&
467         ((dnFileParameter == null) || (! dnFileParameter.hasValue())))
468     {
469       throw new InvalidValueException("Either a single entry DN or a DN file " +
470                                       "URL must be specified.");
471     }
472   }
473
474
475
476   /**
477    * Indicates whether this job class implements logic that makes it possible to
478    * test the validity of job parameters before scheduling the job for execution
479    * (e.g., to see if the server is reachable using the information provided).
480    *
481    * @return <CODE>true</CODE> if this job provides a means of testing the job
482    * parameters, or <CODE>false</CODE> if not.
483    */

484   public boolean providesParameterTest()
485   {
486     return true;
487   }
488
489
490
491   /**
492    * Provides a means of testing the provided job parameters to determine
493    * whether they are valid (e.g., to see if the server is reachable) before
494    * scheduling the job for execution. This method will be executed by the
495    * SLAMD server system itself and not by any of the clients.
496    *
497    * @param parameters The job parameters to be tested.
498    * @param outputMessages The lines of output that were generated as part of
499    * the testing process. Each line of output should
500    * be added to this list as a separate string, and
501    * empty strings (but not <CODE>null</CODE> values)
502    * are allowed to provide separation between
503    * different messages. No formatting should be
504    * provided for these messages, however, since they
505    * may be displayed in either an HTML or plain text
506    * interface.
507    *
508    * @return <CODE>true</CODE> if the test completed successfully, or
509    * <CODE>false</CODE> if not. Note that even if the test did not
510    * complete successfully, the user will be presented with a warning
511    * but will still be allowed to schedule the job using the provided
512    * parameters. This is necessary because the parameters may still be
513    * valid even if the server couldn't validate them at the time the
514    * job was scheduled (e.g., if the server wasn't running or could not
515    * be reached by the SLAMD server even though it could be by the
516    * clients).
517    */

518   public boolean testJobParameters(ParameterList parameters,
519                                    ArrayList outputMessages)
520   {
521     // Get all the parameters that we might need to perform the test.
522
StringParameter hostParam =
523          parameters.getStringParameter(hostParameter.getName());
524     if ((hostParam == null) || (! hostParam.hasValue()))
525     {
526       outputMessages.add("ERROR: No directory server address was provided.");
527       return false;
528     }
529     String JavaDoc host = hostParam.getStringValue();
530
531
532     IntegerParameter portParam =
533          parameters.getIntegerParameter(portParameter.getName());
534     if ((portParam == null) || (! hostParam.hasValue()))
535     {
536       outputMessages.add("ERROR: No directory server port was provided.");
537       return false;
538     }
539     int port = portParam.getIntValue();
540
541
542     boolean useSSL = false;
543     BooleanParameter useSSLParam =
544          parameters.getBooleanParameter(useSSLParameter.getName());
545     if (useSSLParam != null)
546     {
547       useSSL = useSSLParam.getBooleanValue();
548     }
549
550
551     boolean blindTrust = true;
552     BooleanParameter blindTrustParam =
553          parameters.getBooleanParameter(blindTrustParameter.getName());
554     if (blindTrustParam != null)
555     {
556       blindTrust = blindTrustParam.getBooleanValue();
557     }
558
559
560     String JavaDoc keyStore = null;
561     StringParameter keyStoreParam =
562          parameters.getStringParameter(keyStoreParameter.getName());
563     if ((keyStoreParam != null) && keyStoreParam.hasValue())
564     {
565       keyStore = keyStoreParam.getStringValue();
566       File keyStoreFile = new File(keyStore);
567       if (useSSL && (! blindTrust) && (! keyStoreFile.exists()))
568       {
569         outputMessages.add("WARNING: Key store file \"" + keyStore +
570                            "\" not found on SLAMD server system. This test " +
571                            "will blindly trust any SSL certificate " +
572                            "presented by the directory server.");
573         outputMessages.add("");
574         blindTrust = true;
575       }
576       else
577       {
578         System.setProperty(SSL_KEY_STORE_PROPERTY, keyStore);
579       }
580     }
581
582
583     String JavaDoc keyStorePassword = "";
584     StringParameter keyPassParam =
585          parameters.getStringParameter(keyPWParameter.getName());
586     if ((keyPassParam != null) && keyPassParam.hasValue())
587     {
588       keyStorePassword = keyPassParam.getStringValue();
589       System.setProperty(SSL_KEY_PASSWORD_PROPERTY, keyStorePassword);
590     }
591
592
593     String JavaDoc trustStore = null;
594     StringParameter trustStoreParam =
595          parameters.getStringParameter(trustStoreParameter.getName());
596     if ((trustStoreParam != null) && trustStoreParam.hasValue())
597     {
598       trustStore = trustStoreParam.getStringValue();
599       File trustStoreFile = new File(trustStore);
600       if (useSSL && (! blindTrust) && (! trustStoreFile.exists()))
601       {
602         outputMessages.add("WARNING: trust store file \"" + trustStore +
603                            "\" not found on SLAMD server system. This test " +
604                            "will blindly trust any SSL certificate " +
605                            "presented by the directory server.");
606         outputMessages.add("");
607         blindTrust = true;
608       }
609       else
610       {
611         System.setProperty(SSL_TRUST_STORE_PROPERTY, trustStore);
612       }
613     }
614
615
616     String JavaDoc trustStorePassword = "";
617     StringParameter trustPassParam =
618          parameters.getStringParameter(trustPWParameter.getName());
619     if ((trustPassParam != null) && trustPassParam.hasValue())
620     {
621       trustStorePassword = trustPassParam.getStringValue();
622       System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, trustStorePassword);
623     }
624
625
626     String JavaDoc bindDN = "";
627     StringParameter bindDNParam =
628          parameters.getStringParameter(bindDNParameter.getName());
629     if ((bindDNParam != null) && bindDNParam.hasValue())
630     {
631       bindDN = bindDNParam.getStringValue();
632     }
633
634
635     String JavaDoc bindPassword = "";
636     PasswordParameter bindPWParam =
637          parameters.getPasswordParameter(bindPWParameter.getName());
638     if ((bindPWParam != null) && bindPWParam.hasValue())
639     {
640       bindPassword = bindPWParam.getStringValue();
641     }
642
643
644     String JavaDoc proxyAsDN = null;
645     StringParameter proxyAsDNParam =
646          parameters.getStringParameter(proxyAsDNParameter.getName());
647     if ((proxyAsDNParam != null) && proxyAsDNParam.hasValue())
648     {
649       proxyAsDN = proxyAsDNParam.getStringValue();
650     }
651
652
653     // Create the LDAPConnection object that we will use to communicate with the
654
// directory server.
655
LDAPConnection conn;
656     if (useSSL)
657     {
658       if (blindTrust)
659       {
660         try
661         {
662           conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
663         }
664         catch (Exception JavaDoc e)
665         {
666           outputMessages.add("ERROR: Unable to instantiate the blind trust " +
667                              "socket factory for use in creating the SSL " +
668                              "connection: " + stackTraceToString(e));
669           return false;
670         }
671       }
672       else
673       {
674         conn = new LDAPConnection(new JSSESocketFactory(null));
675       }
676     }
677     else
678     {
679       conn = new LDAPConnection();
680     }
681
682
683     // Attempt to establish a connection to the directory server.
684
try
685     {
686       if (useSSL)
687       {
688         outputMessages.add("Attempting to establish an SSL-based connection " +
689                            "to " + host + ":" + port + "....");
690       }
691       else
692       {
693         outputMessages.add("Attempting to establish a connection to " + host +
694                            ":" + port + "....");
695       }
696       conn.connect(host, port);
697       outputMessages.add("Connected successfully.");
698       outputMessages.add("");
699     }
700     catch (Exception JavaDoc e)
701     {
702       outputMessages.add("ERROR: Unable to connect to the directory " +
703                          "server: " + stackTraceToString(e));
704       return false;
705     }
706
707
708     // Attempt to bind to the directory server using the bind DN and password.
709
try
710     {
711       outputMessages.add("Attempting to perform an LDAPv3 bind to the " +
712                          "directory server with a DN of '" + bindDN + "'....");
713       conn.bind(3, bindDN, bindPassword);
714       outputMessages.add("Bound successfully.");
715       outputMessages.add("");
716     }
717     catch (Exception JavaDoc e)
718     {
719       try
720       {
721         conn.disconnect();
722       } catch (Exception JavaDoc e2) {}
723
724       outputMessages.add("ERROR: Unable to bind to the directory server: " +
725                          stackTraceToString(e));
726       return false;
727     }
728
729
730     // If a proxy user was specified, make sure that it exists.
731
if (proxyAsDN != null)
732     {
733       try
734       {
735         outputMessages.add("Checking to make sure that the proxied user '" +
736                            proxyAsDN + "' exists in the directory....");
737         LDAPEntry proxyUserEntry = conn.read(proxyAsDN, new String JavaDoc[] { "1.1" });
738         if (proxyUserEntry == null)
739         {
740           try
741           {
742             conn.disconnect();
743           } catch (Exception JavaDoc e2) {}
744
745           outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
746                              "entry.");
747           return false;
748         }
749         else
750         {
751           outputMessages.add("Successfully read the proxied user's entry.");
752           outputMessages.add("");
753         }
754       }
755       catch (Exception JavaDoc e)
756       {
757         try
758         {
759           conn.disconnect();
760         } catch (Exception JavaDoc e2) {}
761
762         outputMessages.add("ERROR: Unable to retrieve the proxied user's " +
763                            "entry: " + stackTraceToString(e));
764         return false;
765       }
766     }
767
768
769     // At this point, all tests have passed. Close the connection and return
770
// true.
771
try
772     {
773       conn.disconnect();
774     } catch (Exception JavaDoc e) {}
775
776     outputMessages.add("All tests completed successfully.");
777     return true;
778   }
779
780
781
782   /**
783    * Initializes all of the instance variables that correspond to job
784    * parameters.
785    *
786    * @param clientID The client ID for the current client.
787    * @param parameters The set of parameters that have been defined for this
788    * job.
789    *
790    * @throws UnableToRunException If any part of the initialization fails.
791    */

792   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
793          throws UnableToRunException
794   {
795     // Get the address of the target directory server
796
ldapHost = null;
797     hostParameter = parameters.getStringParameter(hostParameter.getName());
798     if (hostParameter != null)
799     {
800       ldapHost = hostParameter.getStringValue();
801     }
802
803     // Get the port for the target directory server
804
ldapPort = 389;
805     portParameter = parameters.getIntegerParameter(portParameter.getName());
806     if (portParameter != null)
807     {
808       ldapPort = portParameter.getIntValue();
809     }
810
811     // Get the bind DN for the target directory server
812
bindDN = "";
813     bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
814     if (bindDNParameter != null)
815     {
816       bindDN = bindDNParameter.getStringValue();
817     }
818
819     // Get the bind password for the target directory server
820
bindPassword = "";
821     bindPWParameter =
822          parameters.getPasswordParameter(bindPWParameter.getName());
823     if (bindPWParameter != null)
824     {
825       bindPassword = bindPWParameter.getStringValue();
826     }
827
828     // Get the DN of the proxy as user.
829
useProxyAuth = false;
830     proxyAsDNParameter =
831          parameters.getStringParameter(proxyAsDNParameter.getName());
832     if ((proxyAsDNParameter != null) && (proxyAsDNParameter.hasValue()))
833     {
834       useProxyAuth = true;
835       proxyAsDN = proxyAsDNParameter.getStringValue();
836     }
837
838     // Get the DN of the entry to compare
839
useDNFile = false;
840     entryDNParameter =
841          parameters.getStringParameter(entryDNParameter.getName());
842     if (entryDNParameter != null)
843     {
844       String JavaDoc entryDN = entryDNParameter.getStringValue();
845       useDNRange = true;
846       useSequential = false;
847
848       try
849       {
850         int openPos = entryDN.indexOf('[');
851         int dashPos = entryDN.indexOf('-', openPos);
852         if (dashPos < 0)
853         {
854           dashPos = entryDN.indexOf(':', openPos);
855           useSequential = true;
856         }
857
858         int closePos = entryDN.indexOf(']', dashPos);
859
860         dnInitial = entryDN.substring(0, openPos);
861         dnFinal = entryDN.substring(closePos+1);
862
863         dnRangeMin = Integer.parseInt(entryDN.substring(openPos+1, dashPos));
864         dnRangeMax = Integer.parseInt(entryDN.substring(dashPos+1, closePos));
865         dnRangeSpan = dnRangeMax - dnRangeMin + 1;
866         sequentialCounter = dnRangeMin;
867       }
868       catch (Exception JavaDoc e)
869       {
870         useDNRange = false;
871         dnInitial = entryDN;
872       }
873     }
874
875     dnURLParameter = parameters.getFileURLParameter(dnURLParameter.getName());
876     if ((dnURLParameter != null) && dnURLParameter.hasValue())
877     {
878       try
879       {
880         useDNFile = true;
881         compDNs = dnURLParameter.getNonBlankFileLines();
882       }
883       catch (Exception JavaDoc e)
884       {
885         throw new UnableToRunException("Could not retrieve the DNs of the " +
886                                        "entries to be compared.", e);
887       }
888     }
889
890     // Get the attribute to compare
891
attribute = "description";
892     attributeParameter =
893          parameters.getStringParameter(attributeParameter.getName());
894     if (attributeParameter != null)
895     {
896       attribute = attributeParameter.getStringValue();
897     }
898
899     // Get the warm up time.
900
warmUpTime = 0;
901     warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
902     if (warmUpParameter != null)
903     {
904       warmUpTime = warmUpParameter.getIntValue();
905     }
906
907     // Get the cool down time.
908
coolDownTime = 0;
909     coolDownParameter =
910          parameters.getIntegerParameter(coolDownParameter.getName());
911     if (coolDownParameter != null)
912     {
913       coolDownTime = coolDownParameter.getIntValue();
914     }
915
916     // Get the delay between requests.
917
delay = 0;
918     delayParameter = parameters.getIntegerParameter(delayParameter.getName());
919     if (delayParameter != null)
920     {
921       delay = delayParameter.getIntValue();
922     }
923
924     // Get the number of iterations to perform
925
iterations = -1;
926     iterationsParameter =
927          parameters.getIntegerParameter(iterationsParameter.getName());
928     if (iterationsParameter != null)
929     {
930       iterations = iterationsParameter.getIntValue();
931     }
932
933     // Get the flag indicating whether we should use SSL or not
934
useSSL = false;
935     useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
936     if (useSSLParameter != null)
937     {
938       useSSL = useSSLParameter.getBooleanValue();
939     }
940
941     // If we are to use SSL, then get all the other SSL-related info
942
if (useSSL)
943     {
944       // Whether to blindly trust any SSL certificate.
945
blindTrustParameter =
946            parameters.getBooleanParameter(blindTrustParameter.getName());
947       if (blindTrustParameter != null)
948       {
949         blindTrust = blindTrustParameter.getBooleanValue();
950       }
951
952       // The location of the JSSE key store
953
sslKeyStore = null;
954       keyStoreParameter =
955            parameters.getStringParameter(keyStoreParameter.getName());
956       if ((keyStoreParameter != null) && (keyStoreParameter.hasValue()))
957       {
958         sslKeyStore = keyStoreParameter.getStringValue();
959         System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
960       }
961
962       // The JSSE key store password
963
sslKeyPassword = null;
964       keyPWParameter =
965            parameters.getPasswordParameter(keyPWParameter.getName());
966       if ((keyPWParameter != null) && (keyPWParameter.hasValue()))
967       {
968         sslKeyPassword = keyPWParameter.getStringValue();
969         System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPassword);
970       }
971
972       // The location of the JSSE trust store
973
sslTrustStore = null;
974       trustStoreParameter =
975            parameters.getStringParameter(trustStoreParameter.getName());
976       if ((trustStoreParameter != null) && (trustStoreParameter.hasValue()))
977       {
978         sslTrustStore = trustStoreParameter.getStringValue();
979         System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
980       }
981
982       // The JSSE trust store password
983
sslTrustPassword = null;
984       trustPWParameter =
985            parameters.getPasswordParameter(trustPWParameter.getName());
986       if ((trustPWParameter != null) && (trustPWParameter.hasValue()))
987       {
988         sslTrustPassword = trustPWParameter.getStringValue();
989         System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPassword);
990       }
991     }
992
993     // Get the flag indicating whether we should disconnect after each compare.
994
alwaysDisconnect = false;
995     disconnectParameter =
996          parameters.getBooleanParameter(disconnectParameter.getName());
997     if (disconnectParameter != null)
998     {
999       alwaysDisconnect = disconnectParameter.getBooleanValue();
1000    }
1001
1002
1003    // Initialize the parent random number generator
1004
parentRandom = new Random();
1005  }
1006
1007
1008
1009  /**
1010   * Initializes this job thread to be used to actually run the job on the
1011   * client. The provided parameter list should be processed to customize the
1012   * behavior of this job thread, and any other initialization that needs to be
1013   * done in order for the job to run should be performed here as well.
1014   *
1015   * @param clientID The client ID for this job thread.
1016   * @param threadID The thread ID for this job thread.
1017   * @param collectionInterval The length of time in seconds to use as the
1018   * statistics collection interval.
1019   * @param parameters The set of parameters provided to this job that
1020   * can be used to customize its behavior.
1021   *
1022   * @throws UnableToRunException If a problem occurs that prevents the thread
1023   * from being able to run properly.
1024   */

1025  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1026                               int collectionInterval, ParameterList parameters)
1027         throws UnableToRunException
1028  {
1029    // Set up the stat trackers
1030
compCount = new IncrementalTracker(clientID, threadID,
1031                                      STAT_TRACKER_COMP_COUNT,
1032                                      collectionInterval);
1033    exceptionsCaught = new IncrementalTracker(clientID, threadID,
1034                                              STAT_TRACKER_EXCEPTIONS_CAUGHT,
1035                                              collectionInterval);
1036    compTime = new TimeTracker(clientID, threadID, STAT_TRACKER_COMP_TIME,
1037                              collectionInterval);
1038
1039
1040    // Enable real-time reporting of the data for these stat trackers.
1041
RealTimeStatReporter statReporter = getStatReporter();
1042    if (statReporter != null)
1043    {
1044      String JavaDoc jobID = getJobID();
1045      compCount.enableRealTimeStats(statReporter, jobID);
1046      exceptionsCaught.enableRealTimeStats(statReporter, jobID);
1047      compTime.enableRealTimeStats(statReporter, jobID);
1048    }
1049
1050
1051    // Initialize the random number generator for this thread.
1052
random = new Random(parentRandom.nextLong());
1053
1054
1055    // If the connection is to use SSL, then establish a preliminary connection
1056
// now. The first connection can take a significant amount of time to
1057
// establish, and we want to get it out of the way early before the timer
1058
// starts (if a duration is specified). Don't worry about any exceptions
1059
// that may get thrown here because there's no easy way to report them back
1060
// but they will be repeated and handled when the job starts running anyway,
1061
// so no big deal.
1062
if (useSSL)
1063    {
1064      try
1065      {
1066        LDAPConnection conn;
1067        if (blindTrust)
1068        {
1069          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1070        }
1071        else
1072        {
1073          conn = new LDAPConnection(new JSSESocketFactory(null));
1074        }
1075
1076        conn.connect(3, ldapHost, ldapPort, bindDN, bindPassword);
1077        conn.disconnect();
1078      }
1079      catch (Exception JavaDoc e) {}
1080    }
1081  }
1082
1083
1084
1085  /**
1086   * Perform the work of this job thread by establishing the connection(s) to
1087   * the directory server and issuing all the appropriate queries. The job will
1088   * continue until the specified number of iterations have been performed, the
1089   * stop time has been reached, the maximum duration has been reached, or the
1090   * SLAMD server indicates that a stop has been requested.
1091   */

1092  public void runJob()
1093  {
1094    // Determine the range of time for which we should collect statistics.
1095
long currentTime = System.currentTimeMillis();
1096    boolean collectingStats = false;
1097    long startCollectingTime = currentTime + (1000 * warmUpTime);
1098    long stopCollectingTime = Long.MAX_VALUE;
1099    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1100    {
1101      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1102    }
1103
1104    // Set a variable that we can use to determine if the connection is alive or
1105
// not
1106
boolean connected = false;
1107
1108    // Set a variable that can be used to determine how long we should sleep
1109
// between compares.
1110
long compStartTime = 0;
1111
1112    // First, see if this should operate "infinitely" (i.e., not a fixed number
1113
// of iterations
1114
boolean infinite = (iterations <= 0);
1115
1116    // Create a variable that we will use for the LDAP connection
1117
if (useSSL)
1118    {
1119      if (blindTrust)
1120      {
1121        try
1122        {
1123          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1124        }
1125        catch (LDAPException le)
1126        {
1127          logMessage(le.getMessage());
1128          indicateStoppedDueToError();
1129          return;
1130        }
1131      }
1132      else
1133      {
1134        conn = new LDAPConnection(new JSSESocketFactory(null));
1135      }
1136    }
1137    else
1138    {
1139      conn = new LDAPConnection();
1140    }
1141
1142
1143    // Create a loop that will run until it needs to stop
1144
for (int i=0; ((! shouldStop()) && ((infinite || (i < iterations)))); i++)
1145    {
1146      currentTime = System.currentTimeMillis();
1147      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1148          (currentTime < stopCollectingTime))
1149      {
1150        // Tell the stat trackers that they should start tracking now
1151
compCount.startTracker();
1152        exceptionsCaught.startTracker();
1153        compTime.startTracker();
1154        collectingStats = true;
1155      }
1156      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1157      {
1158        compCount.stopTracker();
1159        exceptionsCaught.stopTracker();
1160        compTime.stopTracker();
1161        collectingStats = false;
1162      }
1163
1164      // If the connection is currently not connected, then establish it
1165
if (! connected)
1166      {
1167        try
1168        {
1169          conn.connect(3, ldapHost, ldapPort, bindDN, bindPassword);
1170          connected = true;
1171        }
1172        catch (LDAPException le)
1173        {
1174          logMessage("ERROR -- Could not connect to " + ldapHost + ":" +
1175                           ldapPort + " (" + le + ") -- aborting thread");
1176          if (collectingStats)
1177          {
1178            exceptionsCaught.increment();
1179          }
1180          indicateStoppedDueToError();
1181          break;
1182        }
1183      }
1184
1185      LDAPConstraints constraints = conn.getConstraints();
1186      if (useProxyAuth)
1187      {
1188        LDAPProxiedAuthControl proxyAuthControl =
1189             new LDAPProxiedAuthControl(proxyAsDN, true);
1190        constraints.setServerControls(proxyAuthControl);
1191      }
1192
1193
1194      // Create a flag used to determine if the compare was successful.
1195
boolean successful = false;
1196
1197
1198      // Record the current time as the start of the compare.
1199
if (collectingStats)
1200      {
1201        compTime.startTimer();
1202      }
1203      if (delay > 0)
1204      {
1205        compStartTime = System.currentTimeMillis();
1206      }
1207
1208
1209      // Perform the comparison.
1210
try
1211      {
1212        LDAPAttribute attr = new LDAPAttribute(attribute, getRandomString(80));
1213        conn.compare(getRandomEntryDN(), attr, constraints);
1214        successful = true;
1215      }
1216      catch (LDAPException le)
1217      {
1218        writeVerbose("ERROR while performing compare -- " + le);
1219        if (collectingStats)
1220        {
1221          exceptionsCaught.increment();
1222        }
1223        indicateCompletedWithErrors();
1224      }
1225
1226
1227      // Record the current time as the end of the compare.
1228
if (collectingStats)
1229      {
1230        compTime.stopTimer();
1231      }
1232
1233
1234      // Update the appropriate status counters
1235
if (successful && collectingStats)
1236      {
1237        compCount.increment();
1238      }
1239
1240      // If the connection should be broken, then do so
1241
if (alwaysDisconnect)
1242      {
1243        try
1244        {
1245          conn.disconnect();
1246        } catch (LDAPException le) {}
1247        connected = false;
1248      }
1249
1250      // If we need to sleep, then do so
1251
if ((delay > 0) && (! shouldStop()))
1252      {
1253        long now = System.currentTimeMillis();
1254        long sleepTime = delay - (now - compStartTime);
1255        if (sleepTime > 0)
1256        {
1257          try
1258          {
1259            Thread.sleep(sleepTime);
1260          } catch (InterruptedException JavaDoc ie) {}
1261        }
1262      }
1263    }
1264
1265
1266    // If the connection is still established, then close it
1267
try
1268    {
1269      conn.disconnect();
1270    } catch (LDAPException le) {}
1271
1272
1273    // Tell the stat trackers that they should stop tracking
1274
if (collectingStats)
1275    {
1276      compCount.stopTracker();
1277      exceptionsCaught.stopTracker();
1278      compTime.stopTracker();
1279    }
1280  }
1281
1282
1283
1284  /**
1285   * Attempts to force this thread to exit by closing the connection to the
1286   * directory server and setting it to <CODE>null</CODE>.
1287   */

1288  public void destroy()
1289  {
1290    if (conn != null)
1291    {
1292      try
1293      {
1294        conn.disconnect();
1295      } catch (Exception JavaDoc e) {}
1296
1297      conn = null;
1298    }
1299  }
1300
1301
1302
1303  /**
1304   * Retrieves a random DN from the list of DNs that can be compared.
1305   *
1306   * @return A randomly-chosen DN of an entry to compare.
1307   */

1308  public String JavaDoc getRandomEntryDN()
1309  {
1310    if (useDNFile)
1311    {
1312      return compDNs[(random.nextInt() & 0x7FFFFFFF) % compDNs.length];
1313    }
1314    else
1315    {
1316      if (useDNRange)
1317      {
1318        int value;
1319        if (useSequential)
1320        {
1321          value = sequentialCounter++;
1322          if (sequentialCounter > dnRangeMax)
1323          {
1324            sequentialCounter = dnRangeMin;
1325          }
1326        }
1327        else
1328        {
1329          value = ((random.nextInt() & 0x7FFFFFFF) % dnRangeSpan) + dnRangeMin;
1330        }
1331        return dnInitial + value + dnFinal;
1332      }
1333      else
1334      {
1335        return dnInitial;
1336      }
1337    }
1338  }
1339
1340
1341
1342  /**
1343   * Retrieves a string containing the specified number of randomly-chosen
1344   * characters.
1345   *
1346   * @param length The number of characters to include in the string.
1347   *
1348   * @return A string containing the specified number of randomly-chosen
1349   * characters.
1350   */

1351  public String JavaDoc getRandomString(int length)
1352  {
1353    char[] returnChars = new char[length];
1354
1355    for (int i=0; i < length; i++)
1356    {
1357      returnChars[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
1358                                ALPHABET.length];
1359    }
1360
1361    return new String JavaDoc(returnChars);
1362  }
1363}
1364
1365
Popular Tags