KickJava   Java API By Example, From Geeks To Geeks.

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


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

40 public class DelRateJobClass
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 delete.
78    */

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

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

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

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

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

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

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

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

329   public String JavaDoc getJobCategoryName()
330   {
331     return "LDAP";
332   }
333
334
335
336   /**
337    * Overrides the number of clients that may be used for this job to ensure
338    * that only a single client will be used.
339    *
340    * @return The number of clients that will always be used for this job.
341    */

342   public int overrideNumClients()
343   {
344     return 1;
345   }
346
347
348
349   /**
350    * Retrieve a parameter list that can be used to determine all of the
351    * customizeable options that are available for this job.
352    *
353    * @return A parameter list that can be used to determine all of the
354    * customizeable options that are available for this job.
355    */

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

412   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
413                                            int collectionInterval)
414   {
415     return new StatTracker[]
416     {
417       new IncrementalTracker(clientID, threadID, STAT_TRACKER_DELETE_COUNT,
418                              collectionInterval),
419       new TimeTracker(clientID, threadID, STAT_TRACKER_DELETE_TIME,
420                       collectionInterval),
421       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESULT_CODES,
422                              collectionInterval)
423     };
424   }
425
426
427
428   /**
429    * Retrieves the stat trackers that are maintained for this job thread.
430    *
431    * @return The stat trackers that are maintained for this job thread.
432    */

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

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

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

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

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

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

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

1301  public void destroy()
1302  {
1303    if (conn != null)
1304    {
1305      try
1306      {
1307        conn.disconnect();
1308      } catch (Exception JavaDoc e) {}
1309
1310      conn = null;
1311    }
1312  }
1313
1314
1315
1316  /**
1317   * Creates a randomly-generated LDAP entry to be added to the directory.
1318   *
1319   * @return The randomly-generated entry.
1320   */

1321  public String JavaDoc getEntryDN()
1322  {
1323    if (entryDNs == null)
1324    {
1325      int value = nextValue++;
1326      if (value > dnMax)
1327      {
1328        return null;
1329      }
1330
1331      return dnInitial + value + dnFinal;
1332    }
1333    else
1334    {
1335      int index = nextValue++;
1336      if (index < entryDNs.length)
1337      {
1338        return entryDNs[index];
1339      }
1340      else
1341      {
1342        return null;
1343      }
1344    }
1345  }
1346}
1347
1348
Popular Tags