KickJava   Java API By Example, From Geeks To Geeks.

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


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.net.*;
22 import java.security.*;
23 import java.util.*;
24 import javax.net.ssl.*;
25 import com.sun.slamd.http.*;
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 HTTP GET
34  * requests against a Web server. All of the configuration for this job class
35  * can be provided through parameters.
36  *
37  *
38  * @author Neil A. Wilson
39  */

40 public class HTTPGetRateJobClass
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 GET.
78    */

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

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

96   public static final String JavaDoc STAT_TRACKER_EXCEPTIONS_CAUGHT =
97        "Exceptions Caught";
98
99
100
101   /**
102    * The display name for the stat tracker that will be used to track the
103    * response codes for the pages retrieved.
104    */

105   public static final String JavaDoc STAT_TRACKER_RESPONSE_CODES = "Response Codes";
106
107
108
109   // The parameter that indicates whether the client should trust any SSL cert.
110
BooleanParameter blindTrustParameter =
111     new BooleanParameter("blind_trust", "Blindly Trust Any Certificate",
112                          "Indicates whether the client should blindly trust " +
113                          "any certificate presented by the server, or " +
114                          "whether the key and trust stores should be used.",
115                          true);
116
117   // The parameter that indicates whether to automatically follow any redirects
118
// that are encountered.
119
BooleanParameter followRedirectsParameter =
120       new BooleanParameter("follow_redirects", "Follow Redirects",
121                            "Indicates whether the client should " +
122                            "automatically follow any HTTP redirects that may " +
123                            "be returned while retrieving a URL.", true);
124
125   // The parameter that indicates whether associated files should automatically
126
// be retrieved.
127
BooleanParameter retrieveAssociatedFilesParameter =
128        new BooleanParameter("retrieve_associated_files",
129                             "Retrieve Associated Files",
130                             "Indicates wheter to automatically retrieve " +
131                             "associated files (e.g., images, frames, remote " +
132                             "stylesheets, etc.) when retrieving an HTML " +
133                             "document.", false);
134
135   // The parameter that indicates whether to use a persistent connection.
136
BooleanParameter useKeepaliveParameter =
137        new BooleanParameter("use_keepalive", "Use KeepAlive",
138                             "Indicates whether the KeepAlive feature should " +
139                             "be used to keep the connection open for " +
140                             "multiple requests.", false);
141
142   // The parameter that specifies the URL to a file containing a list of URLs to
143
// retrieve.
144
FileURLParameter urlFileParameter =
145       new FileURLParameter("url_file", "File with URLs to Retrieve",
146                            "The URL to a file containing a list of URLs to " +
147                            "retrieve.", null, false);
148
149   // The parameter that specifies the cool down time.
150
IntegerParameter coolDownTimeParameter =
151        new IntegerParameter("cool_down_time", "Cool Down Time",
152                             "The length of time in seconds before the job " +
153                             "stops running that the client should stop " +
154                             "collecting statistics. Note that this cannot " +
155                             "always be accurate, particularly when no stop " +
156                             "time or duration is provided.", true, 0, true, 0,
157                             false, 0);
158
159   // The parameter that specifies the number of iterations.
160
IntegerParameter iterationsParameter =
161        new IntegerParameter("iterations", "Number of Iterations",
162                             "The number of requests that each thread should " +
163                             "issue to the server before completing (a value " +
164                             "less than zero indicates no limit.", true, -1,
165                             false, 0, false, 0);
166
167   // The parameter that specifies the time between requests.
168
IntegerParameter delayParameter =
169        new IntegerParameter("delay", "Time Between Requests (ms)",
170                             "The minimum length of time in milliseconds that " +
171                             "should pass between issuing one request and " +
172                             "issuing the next. Note that if it takes longer " +
173                             "than this length of time to process the request " +
174                             "then no sleep will be performed.", true, 0, true,
175                             0, false, 0);
176
177   // The parameter that specifies the port to use for the proxy server.
178
IntegerParameter proxyPortParameter =
179        new IntegerParameter("proxy_port", "Proxy Server Port",
180                             "The port to use to communicate with the HTTP " +
181                             "proxy server.", false, 8080, true, 1, true, 65535);
182
183   // The parameter that specifies the warm up time.
184
IntegerParameter warmUpTimeParameter =
185        new IntegerParameter("warm_up_time", "Warm Up Time",
186                             "The length of time in seconds before the job " +
187                             "stops running that the client should stop " +
188                             "collecting statistics. Note that this cannot " +
189                             "always be accurate, particularly when no stop " +
190                             "time or duration is provided.", true, 0, true, 0,
191                             false, 0);
192
193   // The parameter that specifies the password for the SSL key store
194
PasswordParameter keyPWParameter =
195        new PasswordParameter("sslkeypw", "SSL Key Store Password",
196                              "The password for the JSSE key store. This " +
197                              "only applies for HTTPS URLs.", false, "");
198
199   // The parameter that specifies the password for the SSL key store
200
PasswordParameter trustPWParameter =
201        new PasswordParameter("ssltrustpw", "SSL Trust Store Password",
202                              "The password for the JSSE trust store. This " +
203                              "only applies for HTTPS URLs.", false, "");
204
205   // A placeholder parameter that is only used for formatting.
206
PlaceholderParameter placeholder = new PlaceholderParameter();
207
208   // The parameter that specifies the location of the SSL key store
209
StringParameter keyStoreParameter =
210        new StringParameter("sslkeystore", "SSL Key Store",
211                            "The path to the JSSE key store to use for an " +
212                            "SSL-based connection. This only applies for " +
213                            "HTTPS URLs.", false, "");
214
215   // The parameter that specifies the address of the proxy server to use.
216
StringParameter proxyHostParameter =
217        new StringParameter("proxy_host", "Proxy Server Address",
218                            "The address of the HTTP proxy server to use if " +
219                            "one is required.", false, "");
220
221   // The parameter that specifies the location of the SSL trust store
222
StringParameter trustStoreParameter =
223        new StringParameter("ssltruststore", "SSL Trust Store",
224                            "The path to the JSSE trust store to use for an " +
225                            "SSL-based connection. This only applies for " +
226                            "HTTPS URLs.", false, "");
227
228   // The parameter that provides the URL to retrieve.
229
StringParameter urlParameter =
230        new StringParameter("url", "URL To Retrieve",
231                            "The URL of the page to be retrieved.", false, "");
232
233
234   // Instance variables that correspond to the parameter values.
235
static boolean blindTrust;
236   static boolean followRedirects;
237   static boolean retrieveAssociatedFiles;
238   static boolean useKeepAlive;
239   static HTTPRequest[] requests;
240   static int coolDownTime;
241   static int numIterations;
242   static int proxyPort;
243   static int timeBetweenRequests;
244   static int warmUpTime;
245   static String JavaDoc proxyHost;
246   static String JavaDoc sslKeyStore;
247   static String JavaDoc sslKeyStorePassword;
248   static String JavaDoc sslTrustStore;
249   static String JavaDoc sslTrustStorePassword;
250
251
252   // The HTTP client that will be used by this thread to actually handle the
253
// requests.
254
HTTPClient httpClient;
255
256
257   // A random number generator to use for the client and the thread.
258
static Random parentRandom;
259   Random random;
260
261
262   // The stat trackers that will be used for this job.
263
CategoricalTracker responseCodes;
264   IncrementalTracker exceptionsCaught;
265   IncrementalTracker requestsPerformed;
266   TimeTracker requestTime;
267
268
269
270   /**
271    * Creates a new instance of this HTTP GetRate job class.
272    */

273   public HTTPGetRateJobClass()
274   {
275     super();
276   }
277
278
279
280   /**
281    * Retrieves the name of the job performed by this job thread.
282    *
283    * @return The name of the job performed by this job thread.
284    */

285   public String JavaDoc getJobName()
286   {
287     return "HTTP GetRate";
288   }
289
290
291
292   /**
293    * Retrieves a description of the job performed by this job thread.
294    *
295    * @return A description of the job performed by this job thread.
296    */

297   public String JavaDoc getJobDescription()
298   {
299     return "This job can be used to issue repeated HTTP GET requests to a " +
300            "Web server to retrieve one or more URLs.";
301   }
302
303
304
305   /**
306    * Retrieves the name of the category in which this job class exists. This is
307    * used to help arrange the job classes in the administrative interface.
308    *
309    * @return The name of the category in which this job class exists.
310    */

311   public String JavaDoc getJobCategoryName()
312   {
313     return "HTTP";
314   }
315
316
317
318   /**
319    * Retrieve a parameter list that can be used to determine all of the
320    * customizeable options that are available for this job.
321    *
322    * @return A parameter list that can be used to determine all of the
323    * customizeable options that are available for this job.
324    */

325   public ParameterList getParameterStubs()
326   {
327     Parameter[] parameters = new Parameter[]
328     {
329       placeholder,
330       urlParameter,
331       urlFileParameter,
332       useKeepaliveParameter,
333       followRedirectsParameter,
334       retrieveAssociatedFilesParameter,
335       placeholder,
336       proxyHostParameter,
337       proxyPortParameter,
338       placeholder,
339       warmUpTimeParameter,
340       coolDownTimeParameter,
341       iterationsParameter,
342       delayParameter,
343       placeholder,
344       blindTrustParameter,
345       keyStoreParameter,
346       keyPWParameter,
347       trustStoreParameter,
348       trustPWParameter
349     };
350
351     return new ParameterList(parameters);
352   }
353
354
355
356   /**
357    * Retrieves the set of stat trackers that will be maintained by this job
358    * class. The stat trackers returned by this method do not have to actually
359    * contain any statistics -- the display name and stat tracker class should
360    * be the only information that callers of this method should rely upon. Note
361    * that this list can be different from the list of statistics actually
362    * collected by the job in some cases (e.g., if the job may not return all the
363    * stat trackers it advertises in all cases, or if the job may return stat
364    * trackers that it did not advertise), but it is a possibility that only the
365    * stat trackers returned by this method will be accessible for some features
366    * in the SLAMD server.
367    *
368    * @param clientID The client ID that should be used for the
369    * returned stat trackers.
370    * @param threadID The thread ID that should be used for the
371    * returned stat trackers.
372    * @param collectionInterval The collection interval that should be used for
373    * the returned stat trackers.
374    *
375    * @return The set of stat trackers that will be maintained by this job
376    * class.
377    */

378   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
379                                            int collectionInterval)
380   {
381     return new StatTracker[]
382     {
383       new IncrementalTracker(clientID, threadID,
384                              STAT_TRACKER_REQUESTS_PERFORMED,
385                              collectionInterval),
386       new TimeTracker(clientID, threadID, STAT_TRACKER_REQUEST_TIME,
387                       collectionInterval),
388       new IncrementalTracker(clientID, threadID, STAT_TRACKER_EXCEPTIONS_CAUGHT,
389                              collectionInterval),
390       new CategoricalTracker(clientID, threadID, STAT_TRACKER_RESPONSE_CODES,
391                              collectionInterval)
392     };
393   }
394
395
396
397   /**
398    * Retrieves the stat trackers that are maintained for this job thread.
399    *
400    * @return The stat trackers that are maintained for this job thread.
401    */

402   public StatTracker[] getStatTrackers()
403   {
404     return new StatTracker[]
405     {
406       requestsPerformed,
407       requestTime,
408       exceptionsCaught,
409       responseCodes
410     };
411   }
412
413
414
415   /**
416    * Provides a means of validating the information used to schedule the job,
417    * including the scheduling information and list of parameters.
418    *
419    * @param numClients The number of clients that should be used to
420    * run the job.
421    * @param threadsPerClient The number of threads that should be created on
422    * each client to run the job.
423    * @param threadStartupDelay The delay in milliseconds that should be used
424    * when starting the client threads.
425    * @param startTime The time that the job should start running.
426    * @param stopTime The time that the job should stop running.
427    * @param duration The maximum length of time in seconds that the
428    * job should be allowed to run.
429    * @param collectionInterval The collection interval that should be used
430    * when gathering statistics for the job.
431    * @param parameters The set of parameters provided to this job that
432    * can be used to customize its behavior.
433    *
434    * @throws InvalidValueException If the provided information is not
435    * appropriate for running this job.
436    */

437   public void validateJobInfo(int numClients, int threadsPerClient,
438                               int threadStartupDelay, Date startTime,
439                               Date stopTime, int duration,
440                               int collectionInterval, ParameterList parameters)
441          throws InvalidValueException
442   {
443     // See if the user has provided either a single URL or a file with a list of
444
// URLs.
445
StringParameter urlParam =
446          parameters.getStringParameter(urlParameter.getName());
447     FileURLParameter urlFileParam =
448          parameters.getFileURLParameter(urlFileParameter.getName());
449
450     if (((urlParam == null) || (! urlParam.hasValue())) &&
451         ((urlFileParam == null) || (! urlFileParam.hasValue())))
452     {
453       throw new InvalidValueException("A value must be provided for either " +
454                                       "the \"" + urlParameter.getDisplayName() +
455                                       "\" parameter or the \"" +
456                                       urlFileParameter.getDisplayName() +
457                                       "\" parameter.");
458     }
459
460
461     if ((urlParam != null) && urlParam.hasValue() &&
462         (urlFileParam != null) && urlFileParam.hasValue())
463     {
464       throw new InvalidValueException("You may not provide a value for both " +
465                                       "the \"" + urlParameter.getDisplayName() +
466                                       "\" parameter and the \"" +
467                                       urlFileParameter.getDisplayName() +
468                                       "\" parameter.");
469     }
470
471
472     if ((urlParam != null) && urlParam.hasValue())
473     {
474       try
475       {
476         URL url = new URL(urlParam.getStringValue());
477       }
478       catch (Exception JavaDoc e)
479       {
480         throw new InvalidValueException("Unable to parse the provided URL \"" +
481                                         urlParam.getStringValue() + "\": " +
482                                         e, e);
483       }
484     }
485   }
486
487
488
489   /**
490    * Indicates whether this job class implements logic that makes it possible to
491    * test the validity of job parameters before scheduling the job for execution
492    * (e.g., to see if the server is reachable using the information provided).
493    *
494    * @return <CODE>true</CODE> if this job provides a means of testing the job
495    * parameters, or <CODE>false</CODE> if not.
496    */

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

531   public boolean testJobParameters(ParameterList parameters,
532                                    ArrayList outputMessages)
533   {
534     // Get the necessary parameter values.
535
URL urlToRetrieve = null;
536     StringParameter urlParam =
537          parameters.getStringParameter(urlParameter.getName());
538     if ((urlParam != null) && urlParam.hasValue())
539     {
540       try
541       {
542         urlToRetrieve = new URL(urlParam.getStringValue());
543       }
544       catch (Exception JavaDoc e)
545       {
546         outputMessages.add("ERROR: Unable to parse URL to retrieve '" +
547                            urlParam.getStringValue() + "': " +
548                            stackTraceToString(e));
549         return false;
550       }
551     }
552     else
553     {
554       FileURLParameter urlFileParam =
555            parameters.getFileURLParameter(urlFileParameter.getName());
556       if ((urlFileParam == null) || (! urlFileParam.hasValue()))
557       {
558         outputMessages.add("ERROR: Either a URL to retrieve or a URL file " +
559                            "must be provided.");
560         return false;
561       }
562       else
563       {
564         try
565         {
566           String JavaDoc[] urls = urlFileParam.getNonBlankFileLines();
567           if ((urls == null) || (urls.length == 0))
568           {
569             outputMessages.add("ERROR: The file containing the URLs to " +
570                                "retrieve, '" +
571                                urlFileParam.getFileURL().toExternalForm() +
572                                "', appears to be empty.");
573             return false;
574           }
575           else
576           {
577             try
578             {
579               urlToRetrieve = new URL(urls[0]);
580             }
581             catch (Exception JavaDoc e)
582             {
583               outputMessages.add("ERROR: Unable to parse URL to retrieve '" +
584                                  urls[0] + "': " + stackTraceToString(e));
585               return false;
586             }
587           }
588         }
589         catch (Exception JavaDoc e)
590         {
591           outputMessages.add("ERROR: Unable to retrieve the URL file '" +
592                              urlFileParam.getFileURL().toExternalForm() +
593                              "': " + stackTraceToString(e));
594         }
595       }
596     }
597
598
599     String JavaDoc proxyHost = null;
600     StringParameter proxyHostParam =
601          parameters.getStringParameter(proxyHostParameter.getName());
602     if ((proxyHostParam != null) && proxyHostParam.hasValue())
603     {
604       proxyHost = proxyHostParam.getStringValue();
605     }
606
607
608     int proxyPort = -1;
609     IntegerParameter proxyPortParam =
610          parameters.getIntegerParameter(proxyPortParameter.getName());
611     if ((proxyPortParam != null) && proxyPortParam.hasValue())
612     {
613       proxyPort = proxyPortParam.getIntValue();
614     }
615
616
617     boolean followRedirects = false;
618     BooleanParameter redirectsParam =
619          parameters.getBooleanParameter(followRedirectsParameter.getName());
620     if (redirectsParam != null)
621     {
622       followRedirects = redirectsParam.getBooleanValue();
623     }
624
625
626     boolean blindTrust = true;
627     BooleanParameter blindTrustParam =
628          parameters.getBooleanParameter(blindTrustParameter.getName());
629     if (blindTrustParam != null)
630     {
631       blindTrust = blindTrustParam.getBooleanValue();
632     }
633
634
635     String JavaDoc keyStore = null;
636     StringParameter keyStoreParam =
637          parameters.getStringParameter(keyStoreParameter.getName());
638     if ((keyStoreParam != null) && keyStoreParam.hasValue())
639     {
640       keyStore = keyStoreParam.getStringValue();
641       File keyStoreFile = new File(keyStore);
642       if ((! blindTrust) && (! keyStoreFile.exists()))
643       {
644         outputMessages.add("WARNING: Key store file \"" + keyStore +
645                            "\" not found on SLAMD server system. This test " +
646                            "will blindly trust any SSL certificate " +
647                            "presented by the directory server.");
648         outputMessages.add("");
649         blindTrust = true;
650       }
651       else
652       {
653         System.setProperty(SSL_KEY_STORE_PROPERTY, keyStore);
654       }
655     }
656
657
658     String JavaDoc keyStorePassword = "";
659     StringParameter keyPassParam =
660          parameters.getStringParameter(keyPWParameter.getName());
661     if ((keyPassParam != null) && keyPassParam.hasValue())
662     {
663       keyStorePassword = keyPassParam.getStringValue();
664       System.setProperty(SSL_KEY_PASSWORD_PROPERTY, keyStorePassword);
665     }
666
667
668     String JavaDoc trustStore = null;
669     StringParameter trustStoreParam =
670          parameters.getStringParameter(trustStoreParameter.getName());
671     if ((trustStoreParam != null) && trustStoreParam.hasValue())
672     {
673       trustStore = trustStoreParam.getStringValue();
674       File trustStoreFile = new File(trustStore);
675       if ((! blindTrust) && (! trustStoreFile.exists()))
676       {
677         outputMessages.add("WARNING: trust store file \"" + trustStore +
678                            "\" not found on SLAMD server system. This test " +
679                            "will blindly trust any SSL certificate " +
680                            "presented by the directory server.");
681         outputMessages.add("");
682         blindTrust = true;
683       }
684       else
685       {
686         System.setProperty(SSL_TRUST_STORE_PROPERTY, trustStore);
687       }
688     }
689
690
691     String JavaDoc trustStorePassword = "";
692     StringParameter trustPassParam =
693          parameters.getStringParameter(trustPWParameter.getName());
694     if ((trustPassParam != null) && trustPassParam.hasValue())
695     {
696       trustStorePassword = trustPassParam.getStringValue();
697       System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, trustStorePassword);
698     }
699
700
701     // Create an HTTPClient to use to retrieve the URL.
702
HTTPClient client = new HTTPClient();
703     client.setFollowRedirects(followRedirects);
704
705     if ((proxyHost != null) && (proxyPort > 0))
706     {
707       client.enableProxy(proxyHost, proxyPort);
708     }
709
710     if (blindTrust)
711     {
712       try
713       {
714         client.setSSLSocketFactory(new JSSEBlindTrustSocketFactory());
715       }
716       catch (Exception JavaDoc e)
717       {
718         outputMessages.add("ERROR: Unable to instantiate blind trust socket " +
719                            "factory: " + stackTraceToString(e));
720         return false;
721       }
722     }
723
724
725     // Construct the request and send it to the server.
726
try
727     {
728       outputMessages.add("Attempting to retrieve URL '" +
729                          urlToRetrieve.toExternalForm() + "'....");
730
731       HTTPRequest request = new HTTPRequest(true, urlToRetrieve);
732       HTTPResponse response = client.sendRequest(request);
733
734       int statusCode = response.getStatusCode();
735       String JavaDoc responseMessage = response.getResponseMessage();
736
737       outputMessages.add("HTTP response status code was " + statusCode + ".");
738       if ((responseMessage != null) && (responseMessage.length() > 0))
739       {
740         outputMessages.add("HTTP response message was " + responseMessage +
741                            ".");
742       }
743
744       outputMessages.add("");
745       outputMessages.add("All tests completed.");
746       client.closeAll();
747       return true;
748     }
749     catch (Exception JavaDoc e)
750     {
751       outputMessages.add("ERROR: Unable to perform the GET: " +
752                          stackTraceToString(e));
753       client.closeAll();
754       return false;
755     }
756   }
757
758
759
760   /**
761    * Performs client-level initialization for this job, including retrieving
762    * the values of all the parameters and reading the filter file (if one has
763    * been specified).
764    *
765    * @param clientID The ID assigned to the client that will be running the
766    * job.
767    * @param parameters The list of parameters defined for this job.
768    *
769    * @throws UnableToRunException If the initialization fails for some reason.
770    */

771   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
772          throws UnableToRunException
773   {
774     urlParameter = parameters.getStringParameter(urlParameter.getName());
775     if ((urlParameter != null) && urlParameter.hasValue())
776     {
777       try
778       {
779         HTTPRequest request =
780              new HTTPRequest(true, new URL(urlParameter.getStringValue()));
781         requests = new HTTPRequest[] { request };
782       }
783       catch (Exception JavaDoc e)
784       {
785         throw new UnableToRunException("Unable to create HTTP request based " +
786                                        "on provided URL \"" +
787                                        urlParameter.getStringValue() + "\": " +
788                                        e, e);
789       }
790     }
791
792     urlFileParameter =
793          parameters.getFileURLParameter(urlFileParameter.getName());
794     if ((urlFileParameter != null) && urlFileParameter.hasValue())
795     {
796       try
797       {
798         String JavaDoc[] urls = urlFileParameter.getFileLines();
799         requests = new HTTPRequest[urls.length];
800         for (int i=0; i < requests.length; i++)
801         {
802           requests[i] = new HTTPRequest(true, new URL(urls[i]));
803         }
804       }
805       catch (Exception JavaDoc e)
806       {
807         throw new UnableToRunException("Unable to obtain or parse the set of " +
808                                        "URLs to retrieve: " + e, e);
809       }
810     }
811
812
813     // See if we should use HTTP keepalive.
814
useKeepAlive = false;
815     useKeepaliveParameter =
816          parameters.getBooleanParameter(useKeepaliveParameter.getName());
817     if (useKeepaliveParameter != null)
818     {
819       useKeepAlive = useKeepaliveParameter.getBooleanValue();
820     }
821
822
823     // See if we should follow redirects.
824
followRedirects = true;
825     followRedirectsParameter =
826          parameters.getBooleanParameter(followRedirectsParameter.getName());
827     if (followRedirectsParameter != null)
828     {
829       followRedirects = followRedirectsParameter.getBooleanValue();
830     }
831
832
833     // See if we should automatically retrieve associated files.
834
retrieveAssociatedFiles = false;
835     retrieveAssociatedFilesParameter =
836          parameters.getBooleanParameter(
837               retrieveAssociatedFilesParameter.getName());
838     if (retrieveAssociatedFilesParameter != null)
839     {
840       retrieveAssociatedFiles =
841            retrieveAssociatedFilesParameter.getBooleanValue();
842     }
843
844
845     // See if we should use a proxy host.
846
proxyHost = null;
847     proxyHostParameter =
848          parameters.getStringParameter(proxyHostParameter.getName());
849     if ((proxyHostParameter != null) && proxyHostParameter.hasValue())
850     {
851       proxyHost = proxyHostParameter.getStringValue();
852     }
853
854
855     // Get the port for the proxy server.
856
proxyPort = -1;
857     proxyPortParameter =
858          parameters.getIntegerParameter(proxyPortParameter.getName());
859     if ((proxyPortParameter != null) && proxyPortParameter.hasValue())
860     {
861       proxyPort = proxyPortParameter.getIntValue();
862     }
863
864
865     // Get the warm up time.
866
warmUpTime = 0;
867     warmUpTimeParameter =
868          parameters.getIntegerParameter(warmUpTimeParameter.getName());
869     if ((warmUpTimeParameter != null) && warmUpTimeParameter.hasValue())
870     {
871       warmUpTime = warmUpTimeParameter.getIntValue();
872     }
873
874
875     // Get the cool down time.
876
coolDownTime = 0;
877     coolDownTimeParameter =
878          parameters.getIntegerParameter(coolDownTimeParameter.getName());
879     if ((coolDownTimeParameter != null) && coolDownTimeParameter.hasValue())
880     {
881       coolDownTime = coolDownTimeParameter.getIntValue();
882     }
883
884
885     // Get the time between requests.
886
timeBetweenRequests = 0;
887     delayParameter = parameters.getIntegerParameter(delayParameter.getName());
888     if ((delayParameter != null) && delayParameter.hasValue())
889     {
890       timeBetweenRequests = delayParameter.getIntValue();
891     }
892
893
894     // Get the number of iterations.
895
numIterations = -1;
896     iterationsParameter =
897          parameters.getIntegerParameter(iterationsParameter.getName());
898     if ((iterationsParameter != null) && iterationsParameter.hasValue())
899     {
900       numIterations = iterationsParameter.getIntValue();
901     }
902
903
904     // Get the arguments related to SSL usage.
905
blindTrustParameter =
906          parameters.getBooleanParameter(blindTrustParameter.getName());
907     if (blindTrustParameter != null)
908     {
909       blindTrust = blindTrustParameter.getBooleanValue();
910     }
911
912     sslKeyStore = null;
913     keyStoreParameter =
914          parameters.getStringParameter(keyStoreParameter.getName());
915     if ((keyStoreParameter != null) && keyStoreParameter.hasValue())
916     {
917       sslKeyStore = keyStoreParameter.getStringValue();
918       System.setProperty(SSL_KEY_STORE_PROPERTY, sslKeyStore);
919     }
920
921     sslKeyStorePassword = null;
922     keyPWParameter =
923          parameters.getPasswordParameter(keyPWParameter.getName());
924     if ((keyPWParameter != null) && keyPWParameter.hasValue())
925     {
926       sslKeyStorePassword = keyPWParameter.getStringValue();
927       System.setProperty(SSL_KEY_PASSWORD_PROPERTY, sslKeyStorePassword);
928     }
929
930     sslTrustStore = null;
931     trustStoreParameter =
932          parameters.getStringParameter(trustStoreParameter.getName());
933     if ((trustStoreParameter != null) && trustStoreParameter.hasValue())
934     {
935       sslTrustStore = trustStoreParameter.getStringValue();
936       System.setProperty(SSL_TRUST_STORE_PROPERTY, sslTrustStore);
937     }
938
939     sslTrustStorePassword = null;
940     trustPWParameter =
941          parameters.getPasswordParameter(trustPWParameter.getName());
942     if ((trustPWParameter != null) && trustPWParameter.hasValue())
943     {
944       sslTrustStorePassword = trustPWParameter.getStringValue();
945       System.setProperty(SSL_TRUST_PASSWORD_PROPERTY, sslTrustStorePassword);
946     }
947
948     parentRandom = new Random();
949   }
950
951
952   /**
953    * Initializes this job thread to be used to actually run the job on the
954    * client. The provided parameter list should be processed to customize the
955    * behavior of this job thread, and any other initialization that needs to be
956    * done in order for the job to run should be performed here as well.
957    *
958    * @param clientID The client ID for this job thread.
959    * @param threadID The thread ID for this job thread.
960    * @param collectionInterval The length of time in seconds to use as the
961    * statistics collection interval.
962    * @param parameters The set of parameters provided to this job that
963    * can be used to customize its behavior.
964    *
965    * @throws UnableToRunException If a problem occurs that prevents the thread
966    * from being able to run properly.
967    */

968   public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
969                                int collectionInterval, ParameterList parameters)
970          throws UnableToRunException
971   {
972     // Initialize the random number generator for this client.
973
random = new Random(parentRandom.nextLong());
974
975
976     // Set up the status counters
977
requestsPerformed = new IncrementalTracker(clientID, threadID,
978                                                STAT_TRACKER_REQUESTS_PERFORMED,
979                                                collectionInterval);
980     requestTime = new TimeTracker(clientID, threadID,
981                                   STAT_TRACKER_REQUEST_TIME,
982                                   collectionInterval);
983     exceptionsCaught = new IncrementalTracker(clientID, threadID,
984                                               STAT_TRACKER_EXCEPTIONS_CAUGHT,
985                                               collectionInterval);
986     responseCodes = new CategoricalTracker(clientID, threadID,
987                                            STAT_TRACKER_RESPONSE_CODES,
988                                            collectionInterval);
989
990
991     // Enable real-time reporting of the data for these stat trackers.
992
RealTimeStatReporter statReporter = getStatReporter();
993     if (statReporter != null)
994     {
995       String JavaDoc jobID = getJobID();
996       requestsPerformed.enableRealTimeStats(statReporter, jobID);
997       requestTime.enableRealTimeStats(statReporter, jobID);
998       exceptionsCaught.enableRealTimeStats(statReporter, jobID);
999     }
1000
1001
1002    // Create and initialize the HTTP client that we will use for handling the
1003
// requests.
1004
httpClient = new HTTPClient();
1005    httpClient.setFollowRedirects(followRedirects);
1006    httpClient.setRetrieveAssociatedFiles(retrieveAssociatedFiles);
1007    httpClient.setUseKeepAlive(useKeepAlive);
1008
1009    if ((proxyHost != null) && (proxyPort > 0))
1010    {
1011      httpClient.enableProxy(proxyHost, proxyPort);
1012    }
1013
1014    if (blindTrust)
1015    {
1016      try
1017      {
1018        httpClient.setSSLSocketFactory(new JSSEBlindTrustSocketFactory());
1019      }
1020      catch (Exception JavaDoc e)
1021      {
1022        throw new UnableToRunException("Unable to use blind trust socket " +
1023                                       "factory: " + e);
1024      }
1025    }
1026  }
1027
1028
1029
1030  /**
1031   * Perform the work of this job thread by establishing the connection(s) to
1032   * the directory server and issuing all the appropriate queries. The job will
1033   * continue until the specified number of iterations have been performed, the
1034   * stop time has been reached, the maximum duration has been reached, or the
1035   * SLAMD server indicates that a stop has been requested.
1036   */

1037  public void runJob()
1038  {
1039    // Determine the range of time for which we should collect statistics.
1040
long currentTime = System.currentTimeMillis();
1041    boolean collectingStats = false;
1042    long startCollectingTime = currentTime + (1000 * warmUpTime);
1043    long stopCollectingTime = Long.MAX_VALUE;
1044    if ((coolDownTime > 0) && (getShouldStopTime() > 0))
1045    {
1046      stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
1047    }
1048
1049    // First, see if this should operate "infinitely" (i.e., not a fixed number
1050
// of iterations
1051
boolean infinite = (numIterations <= 0);
1052
1053    // Create a variable that will be used to handle the delay between requests.
1054
long requestStartTime = 0;
1055
1056
1057    // Create a loop that will run until it needs to stop
1058
for (int i=0; ((! shouldStop()) && ((infinite || (i < numIterations))));
1059         i++)
1060    {
1061      currentTime = System.currentTimeMillis();
1062      if ((! collectingStats) && (currentTime >= startCollectingTime) &&
1063          (currentTime < stopCollectingTime))
1064      {
1065        // Tell the stat trackers that they should start tracking now
1066
requestsPerformed.startTracker();
1067        requestTime.startTracker();
1068        exceptionsCaught.startTracker();
1069        responseCodes.startTracker();
1070        collectingStats = true;
1071      }
1072      else if ((collectingStats) && (currentTime >= stopCollectingTime))
1073      {
1074        requestsPerformed.stopTracker();
1075        requestTime.stopTracker();
1076        exceptionsCaught.stopTracker();
1077        responseCodes.stopTracker();
1078        collectingStats = false;
1079      }
1080
1081      if (timeBetweenRequests > 0)
1082      {
1083        requestStartTime = System.currentTimeMillis();
1084      }
1085
1086      if (collectingStats)
1087      {
1088        requestsPerformed.increment();
1089        requestTime.startTimer();
1090      }
1091
1092      try
1093      {
1094        HTTPResponse response = httpClient.sendRequest(getRandomRequest());
1095
1096        if (collectingStats)
1097        {
1098          responseCodes.increment(String.valueOf(response.getStatusCode()));
1099        }
1100      }
1101      catch (Exception JavaDoc e)
1102      {
1103        if (collectingStats)
1104        {
1105          exceptionsCaught.increment();
1106        }
1107      }
1108
1109      if (collectingStats)
1110      {
1111        requestTime.stopTimer();
1112      }
1113
1114      if (timeBetweenRequests > 0)
1115      {
1116        long requestStopTime = System.currentTimeMillis();
1117        long eTime = requestStopTime - requestStartTime;
1118        long sleepTime = timeBetweenRequests - eTime;
1119        if (sleepTime > 0)
1120        {
1121          try
1122          {
1123            Thread.sleep(sleepTime);
1124          } catch (InterruptedException JavaDoc ie) {}
1125        }
1126      }
1127    }
1128
1129    if (collectingStats)
1130    {
1131      requestsPerformed.stopTracker();
1132      requestTime.stopTracker();
1133      exceptionsCaught.stopTracker();
1134      responseCodes.stopTracker();
1135      collectingStats = false;
1136    }
1137
1138    httpClient.closeAll();
1139  }
1140
1141
1142
1143  /**
1144   * Attempts to force this thread to exit by closing the connection to the
1145   * directory server and setting it to <CODE>null</CODE>.
1146   */

1147  public void destroy()
1148  {
1149    if (httpClient != null)
1150    {
1151      httpClient.closeAll();
1152    }
1153  }
1154
1155
1156
1157  /**
1158   * Retrieves the next request that should be sent.
1159   *
1160   * @return The next request that should be sent.
1161   */

1162  public HTTPRequest getRandomRequest()
1163  {
1164    if (requests.length == 1)
1165    {
1166      return requests[0];
1167    }
1168    else
1169    {
1170      int position = (random.nextInt() & 0x7FFFFFFF) % requests.length;
1171      return requests[position];
1172    }
1173  }
1174}
1175
1176
Popular Tags