KickJava   Java API By Example, From Geeks To Geeks.

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


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.factory.*;
25 import com.sun.slamd.job.*;
26 import com.sun.slamd.parameter.*;
27 import com.sun.slamd.stat.*;
28
29
30
31 /**
32  * This class defines a SLAMD job that performs a search to find one or more
33  * entries, and then performs a modification on each entry found.
34  *
35  *
36  * @author Neil A. Wilson
37  */

38 public class SearchAndModJobClass
39        extends JobClass
40        implements LDAPRebind
41 {
42   /**
43    * The set of characters that will be used to generate random values for the
44    * modifications.
45    */

46   public static final char[] ALPHABET =
47        "abcdefghijklmnopqrstuvwxyz".toCharArray();
48
49
50
51   /**
52    * The system property used to specify the location of the JSSE key store.
53    */

54   public static final String JavaDoc SSL_KEY_STORE_PROPERTY =
55        "javax.net.ssl.keyStore";
56
57
58
59   /**
60    * The system property used to specify the password for the JSSE key store.
61    */

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

70   public static final String JavaDoc SSL_TRUST_STORE_PROPERTY =
71        "javax.net.ssl.trustStore";
72
73
74
75   /**
76    * The system property used to specify the password for the JSSE trust store.
77    */

78   public static final String JavaDoc SSL_TRUST_PASSWORD_PROPERTY =
79        "javax.net.ssl.trustStorePassword";
80
81
82
83   /**
84    * The name of the stat tracker that will be used to keep track of the time
85    * required to perform each modification.
86    */

87   public static final String JavaDoc STAT_TRACKER_MOD_TIME = "Modify Time (ms)";
88
89
90
91   /**
92    * The name of the stat tracker that will be used to keep track of the number
93    * of modify operations performed.
94    */

95   public static final String JavaDoc STAT_TRACKER_NUM_MODS =
96        "Modify Operations Performed";
97
98
99
100   /**
101    * The name of the stat tracker that will be used to keep track of the number
102    * of search operations performed.
103    */

104   public static final String JavaDoc STAT_TRACKER_NUM_SEARCH =
105        "Search Operations Performed";
106
107
108
109   /**
110    * The name of the stat tracker that will be used to keep track of the time
111    * required to perform the search operations.
112    */

113   public static final String JavaDoc STAT_TRACKER_SEARCH_TIME =
114        "Search Time (ms)";
115
116
117
118   /**
119    * The default set of attributes to include in the modification.
120    */

121   public static final String JavaDoc[] DEFAULT_ATTRS_TO_MODIFY = new String JavaDoc[]
122   {
123     "description"
124   };
125
126
127
128   /**
129    * The value to request when there are no attributes to return.
130    */

131   public static final String JavaDoc[] NO_ATTRS = new String JavaDoc[] { "1.1" };
132
133
134
135   // Indicates whether to blindly trust any SSL certificate.
136
static boolean blindTrust;
137
138   // Indicates whether the clients should follow any referrals they may
139
// encounter.
140
static boolean followReferrals;
141
142   // Indicates whether search filters are read from a data file or from
143
// parameters.
144
static boolean useFilterFile;
145
146   // Indicates whether the filter value should be interpreted as a range.
147
static boolean useFilterRange;
148
149   // Indicates whether the filter values should be incremented sequentially.
150
static boolean useSequential;
151
152   // Indicates whether the connection to the directory should use SSL.
153
static boolean useSSL;
154
155   // The time to keep working after stopping statistics collection.
156
static int coolDownTime;
157
158   // The port number of the directory server.
159
static int directoryPort;
160
161   // The maximum value to use in the range of filter values.
162
static int filterMax;
163
164   // The minimum value to use in the range of filter values.
165
static int filterMin;
166
167   // The maximum value to use in the range of filter values.
168
static int filterSpan;
169
170   // The number of iterations per thread.
171
static int numIterations;
172
173   // The next sequential value that should be used when generating filters.
174
static int sequentialCounter;
175
176   // The maximum number of entries to return from a single search operation.
177
static int sizeLimit;
178
179   // The maximum length of time that any single LDAP operation will be allowed
180
// to take before it is cancelled.
181
static int timeLimit;
182
183   // The time to start working before beginning statistics collection.
184
static int warmUpTime;
185
186   // The delay in milliseconds between authentication attempts.
187
static long delay;
188
189   // The random number generator that will seed the thread-specific random
190
// number generators.
191
static Random parentRandom;
192
193   // The DN to use to bind to the directory when performing the search and
194
// modify operations.
195
static String JavaDoc bindDN;
196
197   // The password for the bind DN.
198
static String JavaDoc bindPW;
199
200   // The address of the directory server.
201
static String JavaDoc directoryHost;
202
203   // The text to include after the numeric part of the login ID.
204
static String JavaDoc filterFinal;
205
206   // The text to include before the numeric part of the login ID.
207
static String JavaDoc filterInitial;
208
209   // The DN to use as the search base when trying to find user entries in the
210
// directory.
211
static String JavaDoc searchBase;
212
213   // The path to the JSSE key store to use for SSL.
214
static String JavaDoc sslKeyStore;
215
216   // The password to use to access the JSSE key store.
217
static String JavaDoc sslKeyPassword;
218
219   // The path to the JSSE trust store to use for SSL.
220
static String JavaDoc sslTrustStore;
221
222   // The password to use to access the JSSE trust store.
223
static String JavaDoc sslTrustPassword;
224
225   // The set of login IDs that will be used to authenticate.
226
static String JavaDoc[] filters;
227
228   // The names of the attributes to alter in the modification.
229
static String JavaDoc[] modAttrs;
230
231
232
233   // The parameter that indicates whether the client should trust any SSL cert.
234
BooleanParameter blindTrustParameter =
235     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
236                          "Indicates whether the client should blindly trust " +
237                          "any certificate presented by the server, or " +
238                          "whether the key and trust stores should be used.",
239                          true);
240
241   // The parameter that indicates whether referrals are to be followed or not
242
BooleanParameter followReferralsParameter =
243        new BooleanParameter("followreferrals", "Follow Referrals",
244                             "Indicates whether to follow referrals received " +
245                             "while searching", false);
246
247   // The parameter that indicates whether the connection should use SSL or not
248
BooleanParameter useSSLParameter =
249        new BooleanParameter("usessl", "Use SSL",
250                             "Indicates whether to use SSL to encrypt the " +
251                             "communication with the directory server", false);
252
253   // The parameter used to indicate the login ID/password file.
254
FileURLParameter filterFileParameter =
255        new FileURLParameter("filter_file", "Filter File URL",
256                             "The URL (FILE or HTTP) of the file containing " +
257                             "the search filters to use.", null, false);
258
259   // The parmeter that specifies the cool-down time in seconds.
260
IntegerParameter coolDownParameter =
261        new IntegerParameter("cool_down", "Cool Down Time",
262                             "The time in seconds that the job should " +
263                             "continue searching after ending statistics " +
264                             "collection.", true, 0, true, 0, false, 0);
265
266   // The parameter that indicates the delay that should be used between each
267
// authentication attempt.
268
IntegerParameter delayParameter =
269        new IntegerParameter("delay", "Time Between Searches (ms)",
270                             "Specifies the length of time in milliseconds " +
271                             "each thread should wait between each search/mod " +
272                             "sequence. Note that this delay will be " +
273                             "between the starts of consecutive attempts and " +
274                             "not between the end of one attempt and the " +
275                             "beginning of the next. If a sequence takes " +
276                             "longer than this length of time, then there " +
277                             "will be no delay.", true, 0, true, 0, false, 0);
278
279   // The parameter that indicates the number of times the search should be
280
// performed
281
IntegerParameter iterationsParameter =
282        new IntegerParameter("iterations", "Number of Iterations",
283                             "The number of searches that should be performed " +
284                             "by each thread", false, -1);
285
286   // The parameter used to indicate the port number for the directory server.
287
IntegerParameter portParameter =
288        new IntegerParameter("ldap_port", "Directory Server Port",
289                             "The port number for the directory server.", true,
290                             389, true, 1, true, 65535);
291
292   // The parameter that indicates the maximum number of results to retrieve from
293
// a search.
294
IntegerParameter sizeLimitParameter =
295        new IntegerParameter("sizelimit", "Search Size Limit",
296                             "The maximum number of results to retrieve from " +
297                             "a search operation (0 for unlimited)",
298                             true, 0, true, 0, false, 0);
299
300   // The parameter used to indicate the maximum length of time that any single
301
// LDAP operation will be allowed to take.
302
IntegerParameter timeLimitParameter =
303        new IntegerParameter("time_limit", "Operation Time Limit",
304                             "The maximum length of time in seconds that any " +
305                             "single LDAP operation will be allowed to take " +
306                             "before it is cancelled.", true, 0, true, 0, false,
307                             0);
308
309   // The parmeter that specifies the cool-down time in seconds.
310
IntegerParameter warmUpParameter =
311        new IntegerParameter("warm_up", "Warm Up Time",
312                             "The time in seconds that the job should " +
313                             "search before beginning statistics collection.",
314                             true, 0, true, 0, false, 0);
315
316   // The parameter used to indicate the attributes to modify.
317
MultiLineTextParameter modAttrsParameter =
318        new MultiLineTextParameter("mod_attrs", "Attributes to Modify",
319                                   "The set of attributes to modify.",
320                                   DEFAULT_ATTRS_TO_MODIFY, true);
321
322   // The parameter used to indicate the password for the bind DN.
323
PasswordParameter bindPWParameter =
324        new PasswordParameter("bindpw", "Directory Bind Password",
325                              "The password to use when binding to the " +
326                              "directory server to perform search and modify " +
327                              "operations.", false, "");
328
329   // The parameter that specifies the password for the SSL key store
330
PasswordParameter keyPWParameter =
331     new PasswordParameter("sslkeypw", "SSL Key Store Password",
332                           "The password for the JSSE key store", false, "");
333
334   // The parameter that specifies the password for the SSL key store
335
PasswordParameter trustPWParameter =
336     new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
337                           "The password for the JSSE trust store", false, "");
338
339   // The placeholder parameter used as a spacer in the admin interface.
340
PlaceholderParameter placeholder = new PlaceholderParameter();
341
342   // The parameter used to indicate the bind DN.
343
StringParameter bindDNParameter =
344        new StringParameter("binddn", "Directory Bind DN",
345                            "The DN to use when binding to the directory " +
346                            "server to perform search and modify operations.",
347                            false, "");
348
349   // The parameter used to indicate the search filter.
350
StringParameter filterParameter =
351        new StringParameter("search_filter", "Search Filter",
352                            "The filter to use to search the directory server.",
353                            false, "");
354
355   // The parameter used to indicate the address of the directory server.
356
StringParameter hostParameter =
357        new StringParameter("ldap_host", "Directory Server Address",
358                            "The address for the directory server.", true, "");
359
360   // The parameter that specifies the location of the SSL key store
361
StringParameter keyStoreParameter =
362     new StringParameter("sslkeystore", "SSL Key Store",
363                         "The path to the JSSE key store to use for an " +
364                         "SSL-based connection", false, "");
365
366   // The parameter used to indicate the search base for the directory.
367
StringParameter searchBaseParameter =
368     new StringParameter("search_base", "User Search Base",
369                         "The DN in the directory server under which user " +
370                         "entries may be found.", true, "");
371
372   // The parameter that specifies the location of the SSL trust store
373
StringParameter trustStoreParameter =
374     new StringParameter("ssltruststore", "SSL Trust Store",
375                         "The path to the JSSE trust store to use for an " +
376                         "SSL-based connection", false, "");
377
378   // The stat tracker that will count the number of modify operations performed.
379
IncrementalTracker modCounter;
380
381   // The stat tracker that will count the number of searches performed.
382
IncrementalTracker searchCounter;
383
384   // The connection to the directory server.
385
LDAPConnection conn;
386
387   // The set of constraints to use when performing modifies in the directory.
388
LDAPConstraints modConstraints;
389
390   // The set of constraints to use when performing searches in the directory.
391
LDAPSearchConstraints searchConstraints;
392
393   // The random number generator for this thread.
394
Random random;
395
396   // The stat tracker that will time each modify attempt.
397
TimeTracker modTimer;
398
399   // The stat tracker that will time each search .
400
TimeTracker searchTimer;
401
402
403
404   /**
405    * Creates a new instance of this job thread. This constructor does not need
406    * to do anything other than invoke the constructor for the superclass.
407    */

408   public SearchAndModJobClass()
409   {
410     super();
411   }
412
413
414
415   /**
416    * Returns the user-friendly name that is to be used for this job class in the
417    * administrative interface.
418    *
419    * @return The user-friendly name for this job class.
420    */

421   public String JavaDoc getJobName()
422   {
423     return "LDAP Search and Modify Load Generator";
424   }
425
426
427
428   /**
429    * Returns a description of this job that can be seen in the administrative
430    * interface.
431    *
432    * @return A description of this job class.
433    */

434   public String JavaDoc getJobDescription()
435   {
436     return "This job performs search operations against an LDAP directory " +
437            "server and then performs modifications against each entry " +
438            "returned.";
439   }
440
441
442
443   /**
444    * Retrieves the name of the category in which this job class exists. This is
445    * used to help arrange the job classes in the administrative interface.
446    *
447    * @return The name of the category in which this job class exists.
448    */

449   public String JavaDoc getJobCategoryName()
450   {
451     return "LDAP";
452   }
453
454
455
456   /**
457    * Returns the set of parameters whose value may be specified by the end user.
458    *
459    * @return The set of configurable parameters for this job class.
460    */

461   public ParameterList getParameterStubs()
462   {
463     Parameter[] parameterArray = new Parameter[]
464     {
465       placeholder,
466       hostParameter,
467       portParameter,
468       bindDNParameter,
469       bindPWParameter,
470       placeholder,
471       searchBaseParameter,
472       filterFileParameter,
473       filterParameter,
474       modAttrsParameter,
475       placeholder,
476       warmUpParameter,
477       coolDownParameter,
478       sizeLimitParameter,
479       timeLimitParameter,
480       delayParameter,
481       placeholder,
482       useSSLParameter,
483       blindTrustParameter,
484       keyStoreParameter,
485       keyPWParameter,
486       trustStoreParameter,
487       trustPWParameter,
488       placeholder,
489       iterationsParameter,
490       followReferralsParameter
491     };
492
493     return new ParameterList(parameterArray);
494   }
495
496
497
498   /**
499    * Retrieves the set of stat trackers that will be maintained by this job
500    * class. The stat trackers returned by this method do not have to actually
501    * contain any statistics -- the display name and stat tracker class should
502    * be the only information that callers of this method should rely upon. Note
503    * that this list can be different from the list of statistics actually
504    * collected by the job in some cases (e.g., if the job may not return all the
505    * stat trackers it advertises in all cases, or if the job may return stat
506    * trackers that it did not advertise), but it is a possibility that only the
507    * stat trackers returned by this method will be accessible for some features
508    * in the SLAMD server.
509    *
510    * @param clientID The client ID that should be used for the
511    * returned stat trackers.
512    * @param threadID The thread ID that should be used for the
513    * returned stat trackers.
514    * @param collectionInterval The collection interval that should be used for
515    * the returned stat trackers.
516    *
517    * @return The set of stat trackers that will be maintained by this job
518    * class.
519    */

520   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
521                                            int collectionInterval)
522   {
523     return new StatTracker[]
524     {
525       new IncrementalTracker(clientID, threadID, STAT_TRACKER_NUM_SEARCH,
526                              collectionInterval),
527       new TimeTracker(clientID, threadID, STAT_TRACKER_SEARCH_TIME,
528                       collectionInterval),
529       new IncrementalTracker(clientID, threadID, STAT_TRACKER_NUM_MODS,
530                              collectionInterval),
531       new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_TIME,
532                       collectionInterval)
533     };
534   }
535
536
537
538   /**
539    * Retrieves the set of stat trackers that are maintained by this job class.
540    *
541    * @return The set of stat trackers for this job class.
542    */

543   public StatTracker[] getStatTrackers()
544   {
545     return new StatTracker[]
546     {
547       searchCounter,
548       searchTimer,
549       modCounter,
550       modTimer
551     };
552   }
553
554
555
556   /**
557    * Provides a means of validating the information used to schedule the job,
558    * including the scheduling information and list of parameters.
559    *
560    * @param numClients The number of clients that should be used to
561    * run the job.
562    * @param threadsPerClient The number of threads that should be created on
563    * each client to run the job.
564    * @param threadStartupDelay The delay in milliseconds that should be used
565    * when starting the client threads.
566    * @param startTime The time that the job should start running.
567    * @param stopTime The time that the job should stop running.
568    * @param duration The maximum length of time in seconds that the
569    * job should be allowed to run.
570    * @param collectionInterval The collection interval that should be used
571    * when gathering statistics for the job.
572    * @param parameters The set of parameters provided to this job that
573    * can be used to customize its behavior.
574    *
575    * @throws InvalidValueException If the provided information is not
576    * appropriate for running this job.
577    */

578   public void validateJobInfo(int numClients, int threadsPerClient,
579                               int threadStartupDelay, Date startTime,
580                               Date stopTime, int duration,
581                               int collectionInterval, ParameterList parameters)
582          throws InvalidValueException
583   {
584     FileURLParameter filterURLParameter =
585          parameters.getFileURLParameter(filterFileParameter.getName());
586     if ((filterURLParameter == null) ||
587         (! filterURLParameter.hasValue()))
588     {
589       StringParameter filterValueParameter =
590            parameters.getStringParameter(filterParameter.getName());
591
592       if ((filterValueParameter == null) ||
593           (! filterValueParameter.hasValue()))
594       {
595         throw new InvalidValueException("You must specify either a filter " +
596                                         "file URL or a search filter");
597       }
598     }
599   }
600
601
602
603   /**
604    * Indicates whether this job class implements logic that makes it possible to
605    * test the validity of job parameters before scheduling the job for execution
606    * (e.g., to see if the server is reachable using the information provided).
607    *
608    * @return <CODE>true</CODE> if this job provides a means of testing the job
609    * parameters, or <CODE>false</CODE> if not.
610    */

611   public boolean providesParameterTest()
612   {
613     return true;
614   }
615
616
617
618   /**
619    * Provides a means of testing the provided job parameters to determine
620    * whether they are valid (e.g., to see if the server is reachable) before
621    * scheduling the job for execution. This method will be executed by the
622    * SLAMD server system itself and not by any of the clients.
623    *
624    * @param parameters The job parameters to be tested.
625    * @param outputMessages The lines of output that were generated as part of
626    * the testing process. Each line of output should
627    * be added to this list as a separate string, and
628    * empty strings (but not <CODE>null</CODE> values)
629    * are allowed to provide separation between
630    * different messages. No formatting should be
631    * provided for these messages, however, since they
632    * may be displayed in either an HTML or plain text
633    * interface.
634    *
635    * @return <CODE>true</CODE> if the test completed successfully, or
636    * <CODE>false</CODE> if not. Note that even if the test did not
637    * complete successfully, the user will be presented with a warning
638    * but will still be allowed to schedule the job using the provided
639    * parameters. This is necessary because the parameters may still be
640    * valid even if the server couldn't validate them at the time the
641    * job was scheduled (e.g., if the server wasn't running or could not
642    * be reached by the SLAMD server even though it could be by the
643    * clients).
644    */

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

918   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
919          throws UnableToRunException
920   {
921     // Get the directory server address
922
hostParameter = parameters.getStringParameter(hostParameter.getName());
923     if (hostParameter == null)
924     {
925       throw new UnableToRunException("No directory server host provided.");
926     }
927     else
928     {
929       directoryHost = hostParameter.getStringValue();
930     }
931
932
933     // Get the directory server port
934
portParameter = parameters.getIntegerParameter(portParameter.getName());
935     if (portParameter != null)
936     {
937       directoryPort = portParameter.getIntValue();
938     }
939
940     // Get the DN to use to bind to the directory server.
941
bindDNParameter = parameters.getStringParameter(bindDNParameter.getName());
942     if (bindDNParameter == null)
943     {
944       bindDN = "";
945     }
946     else
947     {
948       bindDN = bindDNParameter.getStringValue();
949     }
950
951     // Get the password to use to bind to the directory server.
952
bindPWParameter =
953          parameters.getPasswordParameter(bindPWParameter.getName());
954     if (bindPWParameter == null)
955     {
956       bindPW = "";
957     }
958     else
959     {
960       bindPW = bindPWParameter.getStringValue();
961     }
962
963     // Get the search base
964
searchBaseParameter =
965          parameters.getStringParameter(searchBaseParameter.getName());
966     if (searchBaseParameter != null)
967     {
968       searchBase = searchBaseParameter.getStringValue();
969     }
970
971
972     // Get the data from the login ID file.
973
useFilterFile = false;
974     filterFileParameter =
975          parameters.getFileURLParameter(filterFileParameter.getName());
976     if ((filterFileParameter != null) && (filterFileParameter.hasValue()))
977     {
978       try
979       {
980         filters = filterFileParameter.getNonBlankFileLines();
981       }
982       catch (Exception JavaDoc e)
983       {
984         throw new UnableToRunException("Unable to retrieve the filter data " +
985                                        "from the file: " + e, e);
986       }
987
988       useFilterFile = true;
989     }
990     else
991     {
992       filterParameter =
993            parameters.getStringParameter(filterParameter.getName());
994       useFilterRange = true;
995       useSequential = false;
996       String JavaDoc filterValue = filterParameter.getStringValue();
997       try
998       {
999         int openPos = filterValue.indexOf('[');
1000        int closePos = filterValue.indexOf(']', openPos);
1001        filterInitial = filterValue.substring(0, openPos);
1002        filterFinal = filterValue.substring(closePos+1);
1003
1004        int dashPos = filterValue.indexOf('-', openPos);
1005        if (dashPos < 0)
1006        {
1007          useSequential = true;
1008          dashPos = filterValue.indexOf(':', openPos);
1009        }
1010
1011
1012        filterMin = Integer.parseInt(filterValue.substring(openPos+1,
1013                                                            dashPos));
1014        filterMax = Integer.parseInt(filterValue.substring(dashPos+1,
1015                                                            closePos));
1016        filterSpan = filterMax - filterMin + 1;
1017        sequentialCounter = filterMin;
1018      }
1019      catch (Exception JavaDoc e)
1020      {
1021        useFilterRange = false;
1022        filterInitial = filterValue;
1023      }
1024    }
1025
1026
1027    // Get the attributes to modify.
1028
modAttrs = null;
1029    modAttrsParameter =
1030         parameters.getMultiLineTextParameter(modAttrsParameter.getName());
1031    if ((modAttrsParameter != null) && (modAttrsParameter.hasValue()))
1032    {
1033      modAttrs = modAttrsParameter.getNonBlankLines();
1034    }
1035
1036    // Get the warm up time.
1037
warmUpTime = 0;
1038    warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
1039    if (warmUpParameter != null)
1040    {
1041      warmUpTime = warmUpParameter.getIntValue();
1042    }
1043
1044    // Get the cool down time.
1045
coolDownTime = 0;
1046    coolDownParameter =
1047         parameters.getIntegerParameter(coolDownParameter.getName());
1048    if (coolDownParameter != null)
1049    {
1050      coolDownTime = coolDownParameter.getIntValue();
1051    }
1052
1053    // Get the max size limit.
1054
sizeLimitParameter =
1055         parameters.getIntegerParameter(sizeLimitParameter.getName());
1056    if (sizeLimitParameter != null)
1057    {
1058      sizeLimit = sizeLimitParameter.getIntValue();
1059    }
1060
1061    // Get the max operation time limit.
1062
timeLimitParameter =
1063         parameters.getIntegerParameter(timeLimitParameter.getName());
1064    if (timeLimitParameter != null)
1065    {
1066      timeLimit = timeLimitParameter.getIntValue();
1067    }
1068
1069    // Get the delay between authentication attempts.
1070
delay = 0;
1071    delayParameter = parameters.getIntegerParameter(delayParameter.getName());
1072    if (delayParameter != null)
1073    {
1074      delay = delayParameter.getIntValue();
1075    }
1076
1077    // Get the flag indicating whether we should use SSL or not
1078
useSSL = false;
1079    useSSLParameter = parameters.getBooleanParameter(useSSLParameter.getName());
1080    if (useSSLParameter != null)
1081    {
1082      useSSL = useSSLParameter.getBooleanValue();
1083    }
1084
1085    // If we are to use SSL, then get all the other SSL-related info
1086
if (useSSL)
1087    {
1088      // Whether to blindly trust any SSL certificate.
1089
blindTrustParameter =
1090           parameters.getBooleanParameter(blindTrustParameter.getName());
1091      if (blindTrustParameter != null)
1092      {
1093        blindTrust = blindTrustParameter.getBooleanValue();
1094      }
1095
1096      // The location of the JSSE key store
1097
sslKeyStore = null;
1098      keyStoreParameter =
1099           parameters.getStringParameter(keyStoreParameter.getName());
1100      if ((keyStoreParameter != null) && (keyStoreParameter.hasValue()))
1101      {
1102        sslKeyStore = keyStoreParameter.getStringValue();
1103        System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
1104      }
1105
1106      // The JSSE key store password
1107
sslKeyPassword = null;
1108      keyPWParameter =
1109           parameters.getPasswordParameter(keyPWParameter.getName());
1110      if ((keyPWParameter != null) && (keyPWParameter.hasValue()))
1111      {
1112        sslKeyPassword = keyPWParameter.getStringValue();
1113        System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyPassword);
1114      }
1115
1116      // The location of the JSSE trust store
1117
sslTrustStore = null;
1118      trustStoreParameter =
1119           parameters.getStringParameter(trustStoreParameter.getName());
1120      if ((trustStoreParameter != null) && (trustStoreParameter.hasValue()))
1121      {
1122        sslTrustStore = trustStoreParameter.getStringValue();
1123        System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
1124      }
1125
1126      // The JSSE trust store password
1127
sslTrustPassword = null;
1128      trustPWParameter =
1129           parameters.getPasswordParameter(trustPWParameter.getName());
1130      if ((trustPWParameter != null) && (trustPWParameter.hasValue()))
1131      {
1132        sslTrustPassword = trustPWParameter.getStringValue();
1133        System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustPassword);
1134      }
1135    }
1136
1137    // Get the number of iterations to perform
1138
numIterations = -1;
1139    iterationsParameter =
1140         parameters.getIntegerParameter(iterationsParameter.getName());
1141    if (iterationsParameter != null)
1142    {
1143      numIterations = iterationsParameter.getIntValue();
1144    }
1145
1146    // Get the flag indicating whether we should follow referrals
1147
followReferrals = false;
1148    followReferralsParameter =
1149         parameters.getBooleanParameter(followReferralsParameter.getName());
1150    if (followReferralsParameter != null)
1151    {
1152      followReferrals = followReferralsParameter.getBooleanValue();
1153    }
1154
1155
1156    // Seed the parent random number generator.
1157
parentRandom = new Random();
1158  }
1159
1160
1161
1162  /**
1163   * Initializes this job class with the information that it will use when
1164   * actually running the job. This will also initialize the stat trackers used
1165   * by the job.
1166   *
1167   * @param clientID The thread ID for this thread.
1168   * @param threadID The thread ID for this thread.
1169   * @param collectionInterval The collection interval to use for gathering
1170   * statistics while processing the job.
1171   * @param parameters The st of parameters that contain the
1172   * information used to customize the way this job
1173   * is processed.
1174   *
1175   * @throws UnableToRunException If a problem occurs that prevents the thread
1176   * from being able to run properly.
1177   */

1178  public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
1179                               int collectionInterval, ParameterList parameters)
1180         throws UnableToRunException
1181  {
1182    // Seed the random number generator for this thread.
1183
random = new Random(parentRandom.nextLong());
1184
1185
1186    // Establish the connection to the directory server.
1187
if (useSSL)
1188    {
1189      if (blindTrust)
1190      {
1191        try
1192        {
1193          conn = new LDAPConnection(new JSSEBlindTrustSocketFactory());
1194        }
1195        catch (LDAPException le)
1196        {
1197          throw new UnableToRunException(le.getMessage(), le);
1198        }
1199      }
1200      else
1201      {
1202        conn = new LDAPConnection(new JSSESocketFactory(null));
1203      }
1204    }
1205    else
1206    {
1207      conn = new LDAPConnection();
1208    }
1209    try
1210    {
1211      conn.connect(3, directoryHost, directoryPort, bindDN, bindPW);
1212      modConstraints = conn.getConstraints();
1213      modConstraints.setTimeLimit(1000*timeLimit);
1214      modConstraints.setRebindProc(this);
1215      modConstraints.setReferrals(followReferrals);
1216      searchConstraints = conn.getSearchConstraints();
1217      searchConstraints.setMaxResults(sizeLimit);
1218      searchConstraints.setServerTimeLimit(timeLimit);
1219      searchConstraints.setTimeLimit(1000*timeLimit);
1220      searchConstraints.setRebindProc(this);
1221      searchConstraints.setReferrals(followReferrals);
1222    }
1223    catch (LDAPException le)
1224    {
1225      throw new UnableToRunException("Could not connect to the directory " +
1226                                     "server: " + le, le);
1227    }
1228
1229
1230    // Create the stat trackers.
1231
modCounter = new IncrementalTracker(clientID, threadID,
1232                                        STAT_TRACKER_NUM_MODS,
1233                                        collectionInterval);
1234    searchCounter = new IncrementalTracker(clientID, threadID,
1235                                           STAT_TRACKER_NUM_SEARCH,
1236                                           collectionInterval);
1237    modTimer = new TimeTracker(clientID, threadID, STAT_TRACKER_MOD_TIME,
1238                               collectionInterval);
1239    searchTimer = new TimeTracker(clientID, threadID,
1240                                  STAT_TRACKER_SEARCH_TIME,
1241                                  collectionInterval);
1242
1243
1244    // Enable real-time reporting of the data for these stat trackers.
1245
RealTimeStatReporter statReporter = getStatReporter();
1246    if (statReporter != null)
1247    {
1248      String JavaDoc jobID = getJobID();
1249      searchCounter.enableRealTimeStats(statReporter, jobID);
1250      modCounter.enableRealTimeStats(statReporter, jobID);
1251      searchTimer.enableRealTimeStats(statReporter, jobID);
1252      modTimer.enableRealTimeStats(statReporter, jobID);
1253    }
1254  }
1255
1256
1257
1258  /**
1259   * Performs the work of actually running the job. When this method completes,
1260   * the job will be done.
1261   */

1262  public void runJob()
1263  {
1264    // Determine the range of time for which we should collect statistics.
1265
long currentTime = System.currentTimeMillis();
1266    boolean collectingStats = false;
1267    long startCollectingTime = currentTime + (1000 * warmUpTime);
1268    long stopCollectingTime = Long.MAX_VALUE;
1269    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1270    {
1271      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1272    }
1273
1274    // Create a list that will be used to hold the entry DNs.
1275
ArrayList dnList = new ArrayList();
1276
1277    // Define a variable that will be used to determine how long to sleep
1278
// between attempts.
1279
long opStartTime = 0;
1280
1281    // Determine if there is a maximum number of iterations.
1282
boolean infinite = (! (numIterations > 0));
1283
1284
1285    // Loop until it is time to stop.
1286
for (int i=0; ((infinite || (i < numIterations)) && (! shouldStop())); i++)
1287    {
1288      currentTime = System.currentTimeMillis();
1289      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1290          (currentTime < stopCollectingTime))
1291      {
1292        // Start all the stat trackers.
1293
searchCounter.startTracker();
1294        searchTimer.startTracker();
1295        modCounter.startTracker();
1296        modTimer.startTracker();
1297        collectingStats = true;
1298      }
1299      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1300      {
1301        searchCounter.stopTracker();
1302        searchTimer.stopTracker();
1303        modCounter.stopTracker();
1304        modTimer.stopTracker();
1305        collectingStats = false;
1306      }
1307
1308      // See if we need to sleep before the next attempt
1309
if ((delay > 0) && (opStartTime > 0))
1310      {
1311        long now = System.currentTimeMillis();
1312        long sleepTime = delay - (now - opStartTime);
1313        if (sleepTime > 0)
1314        {
1315          try
1316          {
1317            Thread.sleep(sleepTime);
1318          } catch (InterruptedException JavaDoc ie) {}
1319
1320          if (shouldStop())
1321          {
1322            break;
1323          }
1324        }
1325      }
1326
1327      // Clear the DN list.
1328
dnList.clear();
1329
1330      // Get a random filter.
1331
String JavaDoc filter = getRandomFilter();
1332
1333
1334      // Start the attempt timer now.
1335
if (delay > 0)
1336      {
1337        opStartTime = System.currentTimeMillis();
1338      }
1339
1340
1341      try
1342      {
1343        // First, issue a search to try to find the user's entry.
1344
LDAPSearchResults results;
1345        if (collectingStats)
1346        {
1347          searchCounter.increment();
1348          searchTimer.startTimer();
1349        }
1350        results = conn.search(searchBase, LDAPConnection.SCOPE_SUB,
1351                              filter, NO_ATTRS, false, searchConstraints);
1352        while (results.hasMoreElements())
1353        {
1354          Object JavaDoc element = results.nextElement();
1355          if (element instanceof LDAPEntry)
1356          {
1357            dnList.add(((LDAPEntry) element).getDN());
1358          }
1359        }
1360        if (collectingStats)
1361        {
1362          searchTimer.stopTimer();
1363        }
1364
1365        // Iterate through each of the entry DNs and perform a modification.
1366
for (int j=0; j < dnList.size(); j++)
1367        {
1368          String JavaDoc dn = (String JavaDoc) dnList.get(j);
1369
1370          LDAPModificationSet modSet = new LDAPModificationSet();
1371          for (int k=0; k < modAttrs.length; k++)
1372          {
1373            LDAPAttribute attr = new LDAPAttribute(modAttrs[k],
1374                                                   getRandomString(80));
1375            modSet.add(LDAPModification.REPLACE, attr);
1376          }
1377          if (collectingStats)
1378          {
1379            modCounter.increment();
1380            modTimer.startTimer();
1381          }
1382          conn.modify(dn, modSet, modConstraints);
1383          if (collectingStats)
1384          {
1385            modTimer.stopTimer();
1386          }
1387        }
1388      }
1389      catch (Exception JavaDoc e)
1390      {
1391        continue;
1392      }
1393    }
1394
1395
1396    // Stop all the stat trackers.
1397
if (collectingStats)
1398    {
1399      searchCounter.stopTracker();
1400      searchTimer.stopTimer();
1401      modCounter.stopTracker();
1402      modTimer.stopTracker();
1403    }
1404
1405    // Close the connection to the directory server.
1406
try
1407    {
1408      conn.disconnect();
1409    } catch (Exception JavaDoc e) {}
1410  }
1411
1412
1413
1414  /**
1415   * Attempts to force this thread to exit by closing the connection to the
1416   * directory server and setting it to <CODE>null</CODE>.
1417   */

1418  public void destroy()
1419  {
1420    if (conn != null)
1421    {
1422      try
1423      {
1424        conn.disconnect();
1425      } catch (Exception JavaDoc e) {}
1426
1427      conn = null;
1428    }
1429  }
1430
1431
1432
1433  /**
1434   * Retrieves an array containing the login ID and password that should be
1435   * used to authenticate to the directory.
1436   *
1437   * @return An array containing the login ID and password.
1438   */

1439  public String JavaDoc getRandomFilter()
1440  {
1441    if (useFilterFile)
1442    {
1443      return filters[(random.nextInt() & 0x7FFFFFFF) % filters.length];
1444    }
1445    else
1446    {
1447      if (useFilterRange)
1448      {
1449        int value;
1450        if (useSequential)
1451        {
1452          value = sequentialCounter++;
1453          if (sequentialCounter > filterMax)
1454          {
1455            sequentialCounter = filterMin;
1456          }
1457        }
1458        else
1459        {
1460          value = ((random.nextInt() & 0x7FFFFFFF) % filterSpan) + filterMin;
1461        }
1462        return filterInitial + value + filterFinal;
1463      }
1464      else
1465      {
1466        return filterInitial;
1467      }
1468    }
1469  }
1470
1471
1472
1473  /**
1474   * Retrieves a string of random characters of the specified length.
1475   *
1476   * @param length The number of characters to include in the string.
1477   *
1478   * @return The generated string of random characters.
1479   */

1480  public String JavaDoc getRandomString(int length)
1481  {
1482    char[] returnArray = new char[length];
1483
1484    for (int i=0; i < returnArray.length; i++)
1485    {
1486      returnArray[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
1487                                ALPHABET.length];
1488    }
1489
1490    return new String JavaDoc(returnArray);
1491  }
1492
1493
1494
1495  /**
1496   * Specifies the credentials that will be used to bind to the target server if
1497   * a referral is encountered. In this case, we will always attempt the bind
1498   * using the same credentials used to bind to the original target.
1499   *
1500   * @param host The address of the directory server targeted by the referral.
1501   * @param port The port of the directory server targeted by the referral.
1502   *
1503   * @return The credentials that will be used to bind to the server targeted
1504   * by the referral.
1505   */

1506  public LDAPRebindAuth getRebindAuthentication(String JavaDoc host, int port)
1507  {
1508    return new LDAPRebindAuth(bindDN, bindPW);
1509  }
1510}
1511
1512
Popular Tags