KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jmeter > engine > StandardJMeterEngine


1 // $Header: /home/cvs/jakarta-jmeter/src/core/org/apache/jmeter/engine/StandardJMeterEngine.java,v 1.43.2.9 2004/12/15 23:34:42 sebb Exp $
2
/*
3  * Copyright 2000-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17 */

18
19 package org.apache.jmeter.engine;
20
21 import java.io.PrintWriter JavaDoc;
22 import java.io.Serializable JavaDoc;
23 import java.io.StringWriter JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.LinkedList JavaDoc;
30 import java.util.List JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import org.apache.jmeter.reporters.ResultCollector;
34 import org.apache.jmeter.testelement.TestElement;
35 import org.apache.jmeter.testelement.TestListener;
36 import org.apache.jmeter.testelement.TestPlan;
37 import org.apache.jmeter.threads.JMeterContextService;
38 import org.apache.jmeter.threads.JMeterThread;
39 import org.apache.jmeter.threads.JMeterThreadMonitor;
40 import org.apache.jmeter.threads.ListenerNotifier;
41 import org.apache.jmeter.threads.TestCompiler;
42 import org.apache.jmeter.threads.ThreadGroup;
43 import org.apache.jorphan.collections.HashTree;
44 import org.apache.jorphan.collections.ListedHashTree;
45 import org.apache.jorphan.collections.SearchByClass;
46 import org.apache.jorphan.logging.LoggingManager;
47 import org.apache.log.Logger;
48
49 /**
50  * @version $Revision: 1.43.2.9 $ Updated on: $Date: 2004/12/15 23:34:42 $
51  */

52 public class StandardJMeterEngine
53     implements JMeterEngine, JMeterThreadMonitor, Runnable JavaDoc, Serializable JavaDoc
54 {
55     transient private static Logger log = LoggingManager.getLoggerForClass();
56     private transient Thread JavaDoc runningThread;
57     private static long WAIT_TO_DIE = 5 * 1000; //5 seconds
58
private transient Map JavaDoc allThreads;
59     private boolean running = false;
60     private boolean serialized = false;
61     private volatile boolean schcdule_run = false;
62     private HashTree test;
63     private transient SearchByClass testListeners;
64     private String JavaDoc host = null;
65     private transient ListenerNotifier notifier;
66     
67     // Allow engine and threads to be stopped from outside a thread
68
// e.g. from beanshell server
69
// Assumes that there is only one instance of the engine
70
// at any one time so it is not guaranteed to work ...
71
private static transient Map JavaDoc allThreadNames;
72     private static StandardJMeterEngine engine;
73     private static Map JavaDoc allThreadsSave;
74     public static void stopEngineNow()
75     {
76         if (engine != null) // May be null if called from Unit test
77
engine.stopTest(true);
78     }
79     public static void stopEngine()
80     {
81         if (engine != null) // May be null if called from Unit test
82
engine.stopTest(false);
83     }
84     public static boolean stopThread(String JavaDoc threadName)
85     {
86         return stopThread(threadName,false);
87     }
88     public static boolean stopThreadNow(String JavaDoc threadName)
89     {
90         return stopThread(threadName,true);
91     }
92     private static boolean stopThread(String JavaDoc threadName, boolean now)
93     {
94         if (allThreadNames == null) return false;// e.g. not yet started
95
JMeterThread thrd;
96         try {
97             thrd = (JMeterThread)allThreadNames.get(threadName);
98         } catch (Exception JavaDoc e) {
99             log.warn("stopThread: "+e);
100             return false;
101         }
102         if (thrd!= null)
103         {
104             thrd.stop();
105             if (now)
106             {
107                 Thread JavaDoc t = (Thread JavaDoc) allThreadsSave.get(thrd);
108                 if (t != null)
109                 {
110                     t.interrupt();
111                 }
112                 
113             }
114             return true;
115         }
116         else
117         {
118             return false;
119         }
120     }
121     // End of code to allow engine to be controlled remotely
122

123     /*
124      * Allow functions etc to register for testStopped notification
125      */

126     private static List JavaDoc testList = null;
127     public static synchronized void register(TestListener tl)
128     {
129         testList.add(tl);
130     }
131     
132     public StandardJMeterEngine()
133     {
134         allThreads = new HashMap JavaDoc();
135         engine=this;
136         allThreadNames = new HashMap JavaDoc();
137         allThreadsSave = allThreads;
138     }
139
140     public StandardJMeterEngine(String JavaDoc host)
141     {
142         this();
143         this.host = host;
144     }
145
146     public void configure(HashTree testTree)
147     {
148         test = testTree;
149     }
150
151     public void setHost(String JavaDoc host)
152     {
153         this.host = host;
154     }
155
156     protected HashTree getTestTree()
157     {
158         return test;
159     }
160
161     protected void compileTree()
162     {
163         PreCompiler compiler = new PreCompiler();
164         getTestTree().traverse(compiler);
165     }
166
167     public void runTest() throws JMeterEngineException
168     {
169         try
170         {
171             runningThread = new Thread JavaDoc(this);
172             runningThread.start();
173         }
174         catch (Exception JavaDoc err)
175         {
176             stopTest();
177             StringWriter JavaDoc string = new StringWriter JavaDoc();
178             PrintWriter JavaDoc writer = new PrintWriter JavaDoc(string);
179             err.printStackTrace(writer);
180             throw new JMeterEngineException(string.toString());
181         }
182     }
183
184     private void removeThreadGroups(List JavaDoc elements)
185     {
186         Iterator JavaDoc iter = elements.iterator();
187         while (iter.hasNext())
188         {
189             Object JavaDoc item = iter.next();
190             if (item instanceof ThreadGroup JavaDoc)
191             {
192                 iter.remove();
193             }
194             else if (!(item instanceof TestElement))
195             {
196                 iter.remove();
197             }
198         }
199     }
200
201     protected void setMode()
202     {
203         SearchByClass testPlan = new SearchByClass(TestPlan.class);
204         getTestTree().traverse(testPlan);
205         Object JavaDoc[] plan = testPlan.getSearchResults().toArray();
206         ResultCollector.enableFunctionalMode(
207             ((TestPlan) plan[0]).isFunctionalMode());
208     }
209
210     protected void notifyTestListenersOfStart()
211     {
212         Iterator JavaDoc iter = testListeners.getSearchResults().iterator();
213         while (iter.hasNext())
214         {
215             TestListener it = (TestListener)iter.next();
216             log.info("Notifying test listener: " + it.getClass().getName());
217             if (host == null)
218             {
219                 it.testStarted();
220             }
221             else
222             {
223                 it.testStarted(host);
224             }
225         }
226     }
227
228     protected void notifyTestListenersOfEnd()
229     {
230         log.info("Notifying listeners of end of test");
231         
232         Iterator JavaDoc iter = testListeners.getSearchResults().iterator();
233         while (iter.hasNext())
234         {
235             TestListener it = (TestListener)iter.next();
236             log.info("Notifying test listener: " + it.getClass().getName());
237             if (host == null)
238             {
239                 it.testEnded();
240             }
241             else
242             {
243                 it.testEnded(host);
244             }
245         }
246         log.info("Test has ended");
247     }
248
249     private ListedHashTree cloneTree(ListedHashTree tree)
250     {
251         TreeCloner cloner = new TreeCloner(true);
252         tree.traverse(cloner);
253         return cloner.getClonedTree();
254     }
255
256     public void reset()
257     {
258         if (running)
259         {
260             stopTest();
261         }
262     }
263
264     public synchronized void threadFinished(JMeterThread thread)
265     {
266         allThreads.remove(thread);
267         if (!serialized && allThreads.size() == 0 && !schcdule_run )
268         {
269             stopTest();
270         }
271     }
272
273     public synchronized void stopTest()
274     {
275         Thread JavaDoc stopThread = new Thread JavaDoc(new StopTest());
276         stopThread.start();
277     }
278
279     public synchronized void stopTest(boolean b)
280     {
281         Thread JavaDoc stopThread = new Thread JavaDoc(new StopTest(b));
282         stopThread.start();
283     }
284     
285     public void askThreadsToStop()
286     {
287         engine.stopTest(false);
288     }
289     
290     private class StopTest implements Runnable JavaDoc
291     {
292         boolean now;
293         private StopTest(){
294             now=true;
295         }
296         private StopTest(boolean b){
297             now=b;
298         }
299         public void run()
300         {
301             if (running)
302             {
303                 running = false;
304                 if (now){
305                     tellThreadsToStop();
306                 } else {
307                     stopAllThreads();
308                 }
309                 try
310                 {
311                     Thread.sleep(10 * allThreads.size());
312                 }
313                 catch (InterruptedException JavaDoc e)
314                 {}
315                 boolean stopped=verifyThreadsStopped();
316                 if (stopped || now){
317                     notifyTestListenersOfEnd();
318                 }
319             }
320         }
321     }
322
323     public void run()
324     {
325         log.info("Running the test!");
326         running = true;
327         testList = new ArrayList JavaDoc();
328
329         SearchByClass testPlan = new SearchByClass(TestPlan.class);
330         getTestTree().traverse(testPlan);
331         Object JavaDoc[] plan = testPlan.getSearchResults().toArray();
332         if (plan.length == 0){
333             System.err.println("Could not find the TestPlan!");
334             log.error("Could not find the TestPlan!");
335             System.exit(1);
336         }
337         if (((TestPlan) plan[0]).isSerialized())
338         {
339             serialized = true;
340         }
341         compileTree();
342         
343         /**
344          * Notification of test listeners needs to happen after function replacement, but before
345          * setting RunningVersion to true.
346          */

347         testListeners = new SearchByClass(TestListener.class);
348         getTestTree().traverse(testListeners);
349         log.info("About to call test listeners");
350         Collection JavaDoc col = testListeners.getSearchResults();
351         col.addAll(testList);
352         testList=null;
353         notifyTestListenersOfStart();
354         
355         getTestTree().traverse(new TurnElementsOn());
356         
357         List JavaDoc testLevelElements =
358             new LinkedList JavaDoc(getTestTree().list(getTestTree().getArray()[0]));
359         removeThreadGroups(testLevelElements);
360         SearchByClass searcher = new SearchByClass(ThreadGroup JavaDoc.class);
361         
362         setMode();
363         getTestTree().traverse(searcher);
364         TestCompiler.initialize();
365         //for each thread group, generate threads
366
// hand each thread the sampler controller
367
// and the listeners, and the timer
368
JMeterThread[] threads;
369         Iterator JavaDoc iter = searcher.getSearchResults().iterator();
370
371         /*
372          * Here's where the test really starts. Run a Full GC now: it's no
373          * harm at all (just delays test start by a tiny amount) and
374          * hitting one too early in the test can impair results for short
375          * tests.
376          */

377         System.gc();
378         
379         
380         notifier = new ListenerNotifier();
381         
382         schcdule_run = true;
383         JMeterContextService.getContext().setSamplingStarted(true);
384         int groupCount = 0;
385         while (iter.hasNext())
386         {
387             groupCount++;
388             ThreadGroup JavaDoc group = (ThreadGroup JavaDoc) iter.next();
389             int numThreads = group.getNumThreads();
390             boolean onErrorStopTest = group.getOnErrorStopTest();
391             boolean onErrorStopThread = group.getOnErrorStopThread();
392             String JavaDoc groupName = group.getName();
393             int rampUp = group.getRampUp();
394             float perThreadDelay = ((float) (rampUp * 1000) / (float) numThreads);
395             threads = new JMeterThread[numThreads];
396             
397             log.info("Starting " + numThreads + " threads for group "+ groupName
398                 + ". Ramp up = "+ rampUp + ".");
399             
400             if (onErrorStopTest) {
401                 log.info("Test will stop on error");
402             } else if (onErrorStopThread) {
403                 log.info("Thread will stop on error");
404             } else {
405                 log.info("Continue on error");
406             }
407
408             for (int i = 0; running && i < threads.length; i++)
409             {
410                 ListedHashTree threadGroupTree =
411                     (ListedHashTree) searcher.getSubTree(group);
412                 threadGroupTree.add(group, testLevelElements);
413                 threads[i] =
414                     new JMeterThread(
415                         cloneTree(threadGroupTree),
416                         this,
417                         notifier);
418                 threads[i].setThreadNum(i);
419                 threads[i].setInitialContext(JMeterContextService.getContext());
420                 threads[i].setInitialDelay((int) (perThreadDelay * (float) i));
421                 String JavaDoc threadName = groupName + " " + groupCount + "-" + (i + 1);
422                 threads[i].setThreadName(threadName);
423
424                 scheduleThread(threads[i], group);
425                 
426                 // Set up variables for stop handling
427
threads[i].setEngine(this);
428                 threads[i].setOnErrorStopTest(onErrorStopTest);
429                 threads[i].setOnErrorStopThread(onErrorStopThread);
430                 
431                 Thread JavaDoc newThread = new Thread JavaDoc(threads[i]);
432                 newThread.setName(threadName);
433                 allThreads.put(threads[i], newThread);
434                 allThreadNames.put(threadName,threads[i]);
435                 if (serialized
436                     && !iter.hasNext()
437                     && i == threads.length - 1) //last thread
438
{
439                     serialized = false;
440                 }
441                 newThread.start();
442             }
443             schcdule_run = false;
444             if (serialized)
445             {
446                 while (running && allThreads.size() > 0)
447                 {
448                     try
449                     {
450                         Thread.sleep(1000);
451                     }
452                     catch (InterruptedException JavaDoc e)
453                     {}
454                 }
455             }
456         }
457     }
458
459     /**
460      * This will schedule the time for the JMeterThread.
461      *
462      * @param thread
463      * @param group
464      */

465     private void scheduleThread(JMeterThread thread, ThreadGroup JavaDoc group)
466     {
467         //if true the Scheduler is enabled
468
if (group.getScheduler())
469         {
470             long now = System.currentTimeMillis();
471             //set the start time for the Thread
472
if (group.getDelay() > 0 ){// Duration is in seconds
473
thread.setStartTime(group.getDelay()*1000+now);
474             } else {
475                 long start = group.getStartTime();
476                 if (start < now) start = now; // Force a sensible start time
477
thread.setStartTime(start);
478             }
479             
480             //set the endtime for the Thread
481
if (group.getDuration() > 0){// Duration is in seconds
482
thread.setEndTime(group.getDuration()*1000+(thread.getStartTime()));
483             } else {
484                 thread.setEndTime(group.getEndTime());
485             }
486
487             //Enables the scheduler
488
thread.setScheduled(true);
489         }
490     }
491
492     private boolean verifyThreadsStopped()
493     {
494         boolean stoppedAll=true;
495         Iterator JavaDoc iter = new HashSet JavaDoc(allThreads.keySet()).iterator();
496         while (iter.hasNext())
497         {
498             Thread JavaDoc t = (Thread JavaDoc) allThreads.get(iter.next());
499             if (t != null && t.isAlive())
500             {
501                 try
502                 {
503                     t.join(WAIT_TO_DIE);
504                 }
505                 catch (InterruptedException JavaDoc e)
506                 {}
507                 if (t.isAlive())
508                 {
509                     stoppedAll=false;
510                     log.info("Thread won't die: " + t.getName());
511                 }
512             }
513         }
514         return stoppedAll;
515     }
516
517     private void tellThreadsToStop()
518     {
519         Iterator JavaDoc iter = new HashSet JavaDoc(allThreads.keySet()).iterator();
520         while (iter.hasNext())
521         {
522             JMeterThread item = (JMeterThread) iter.next();
523             item.stop();
524             Thread JavaDoc t = (Thread JavaDoc) allThreads.get(item);
525             if (t != null)
526             {
527                 t.interrupt();
528             }
529             else
530             {
531                 log.warn("Lost thread: " + item.getThreadName());
532                 allThreads.remove(item);
533             }
534         }
535     }
536     
537     private void stopAllThreads()
538     {
539         Iterator JavaDoc iter = new HashSet JavaDoc(allThreads.keySet()).iterator();
540         while (iter.hasNext())
541         {
542             JMeterThread item = (JMeterThread) iter.next();
543             item.stop();
544         }
545     }
546
547     // Remote exit
548
public void exit()
549     {
550         // Needs to be run in a separate thread to allow RMI call to return OK
551
Thread JavaDoc t = new Thread JavaDoc(){
552             public void run(){
553                 //log.info("Pausing");
554
try
555                 {
556                     Thread.sleep(1000);
557                 }
558                 catch (InterruptedException JavaDoc e)
559                 {
560                 }
561                 log.info("Bye");
562                 System.exit(0);
563             };
564         };
565         log.info("Starting Closedown");
566         t.start();
567     }
568 }
569
Popular Tags