Package org.apache.jmeter.engine

Source Code of org.apache.jmeter.engine.StandardJMeterEngine$StopTest

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

package org.apache.jmeter.engine;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestListener;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterThread;
import org.apache.jmeter.threads.JMeterThreadMonitor;
import org.apache.jmeter.threads.ListenerNotifier;
import org.apache.jmeter.threads.TestCompiler;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.ListedHashTree;
import org.apache.jorphan.collections.SearchByClass;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

/**
* @version    $Revision: 1.43.2.8 $ Updated on: $Date: 2004/10/12 23:45:21 $
*/
public class StandardJMeterEngine
    implements JMeterEngine, JMeterThreadMonitor, Runnable, Serializable
{
    transient private static Logger log = LoggingManager.getLoggerForClass();
    private transient Thread runningThread;
    private static long WAIT_TO_DIE = 5 * 1000; //5 seconds
    private transient Map allThreads;
    private boolean running = false;
    private boolean serialized = false;
    private volatile boolean schcdule_run = false;
    private HashTree test;
    private transient SearchByClass testListeners;
    private String host = null;
    private transient ListenerNotifier notifier;
   
    // Allow engine and threads to be stopped from outside a thread
    // e.g. from beanshell server
    // Assumes that there is only one instance of the engine
    // at any one time so it is not guaranteed to work ...
    private static transient Map allThreadNames;
    private static StandardJMeterEngine engine;
  private static Map allThreadsSave;
    public static void stopEngineNow()
    {
      if (engine != null) // May be null if called from Unit test
        engine.stopTest(true);
    }
    public static void stopEngine()
    {
      if (engine != null// May be null if called from Unit test
        engine.stopTest(false);
    }
    public static boolean stopThread(String threadName)
    {
      return stopThread(threadName,false);
    }
    public static boolean stopThreadNow(String threadName)
    {
      return stopThread(threadName,true);
    }
    private static boolean stopThread(String threadName, boolean now)
    {
      if (allThreadNames == null) return false;// e.g. not yet started
      JMeterThread thrd;
    try {
          thrd = (JMeterThread)allThreadNames.get(threadName);
      } catch (Exception e) {
        log.warn("stopThread: "+e);
        return false;
      }
      if (thrd!= null)
      {
        thrd.stop();
        if (now)
        {
            Thread t = (Thread) allThreadsSave.get(thrd);
            if (t != null)
            {
                t.interrupt();
            }
         
        }
        return true;
      }
      else
      {
        return false;
      }
    }
    // End of code to allow engine to be controlled remotely
   
    /*
     * Allow functions etc to register for testStopped notification
     */
    private static List testList = null;
    public static synchronized void register(TestListener tl)
    {
      testList.add(tl);
    }
   
    public StandardJMeterEngine()
    {
        allThreads = new HashMap();
        engine=this;
        allThreadNames = new HashMap();
        allThreadsSave = allThreads;
    }

    public StandardJMeterEngine(String host)
    {
        this();
        this.host = host;
    }

    public void configure(HashTree testTree)
    {
        test = testTree;
    }

    public void setHost(String host)
    {
        this.host = host;
    }

    protected HashTree getTestTree()
    {
        return test;
    }

    protected void compileTree()
    {
        PreCompiler compiler = new PreCompiler();
        getTestTree().traverse(compiler);
    }

    public void runTest() throws JMeterEngineException
    {
        try
        {
            runningThread = new Thread(this);
            runningThread.start();
        }
        catch (Exception err)
        {
            stopTest();
            StringWriter string = new StringWriter();
            PrintWriter writer = new PrintWriter(string);
            err.printStackTrace(writer);
            throw new JMeterEngineException(string.toString());
        }
    }

    private void removeThreadGroups(List elements)
    {
        Iterator iter = elements.iterator();
        while (iter.hasNext())
        {
            Object item = iter.next();
            if (item instanceof ThreadGroup)
            {
                iter.remove();
            }
            else if (!(item instanceof TestElement))
            {
                iter.remove();
            }
        }
    }

    protected void setMode()
    {
        SearchByClass testPlan = new SearchByClass(TestPlan.class);
        getTestTree().traverse(testPlan);
        Object[] plan = testPlan.getSearchResults().toArray();
        ResultCollector.enableFunctionalMode(
            ((TestPlan) plan[0]).isFunctionalMode());
    }

    protected void notifyTestListenersOfStart()
    {
        Iterator iter = testListeners.getSearchResults().iterator();
        while (iter.hasNext())
        {
          TestListener it = (TestListener)iter.next();
          log.info("Notifying test listener: " + it.getClass().getName());
            if (host == null)
            {
                it.testStarted();
            }
            else
            {
                it.testStarted(host);
            }
        }
    }

    protected void notifyTestListenersOfEnd()
    {
      log.info("Notifying listeners of end of test");
     
        Iterator iter = testListeners.getSearchResults().iterator();
        while (iter.hasNext())
        {
          TestListener it = (TestListener)iter.next();
          log.info("Notifying test listener: " + it.getClass().getName());
            if (host == null)
            {
                it.testEnded();
            }
            else
            {
                it.testEnded(host);
            }
        }
        log.info("Test has ended");
    }

    private ListedHashTree cloneTree(ListedHashTree tree)
    {
        TreeCloner cloner = new TreeCloner(true);
        tree.traverse(cloner);
        return cloner.getClonedTree();
    }

    public void reset()
    {
        if (running)
        {
            stopTest();
        }
    }

    public synchronized void threadFinished(JMeterThread thread)
    {
        allThreads.remove(thread);
        if (!serialized && allThreads.size() == 0 && !schcdule_run )
        {
            stopTest();
        }
    }

    public synchronized void stopTest()
    {
        Thread stopThread = new Thread(new StopTest());
        stopThread.start();
    }

    public synchronized void stopTest(boolean b)
    {
        Thread stopThread = new Thread(new StopTest(b));
        stopThread.start();
    }
   
    public void askThreadsToStop()
    {
      engine.stopTest(false);
    }
   
    private class StopTest implements Runnable
    {
      boolean now;
      private StopTest(){
        now=true;
      }
      private StopTest(boolean b){
        now=b;
      }
        public void run()
        {
            if (running)
            {
                running = false;
                if (now){
                  tellThreadsToStop();
                } else {
                  stopAllThreads();
                }
                try
                {
                    Thread.sleep(10 * allThreads.size());
                }
                catch (InterruptedException e)
                {}
                boolean stopped=verifyThreadsStopped();
                if (stopped || now){
                    notifyTestListenersOfEnd();
                }
            }
        }
    }

    public void run()
    {
        log.info("Running the test!");
        running = true;
        testList = new ArrayList();

        SearchByClass testPlan = new SearchByClass(TestPlan.class);
        getTestTree().traverse(testPlan);
        Object[] plan = testPlan.getSearchResults().toArray();
        if (plan.length == 0){
      System.err.println("Could not find the TestPlan!");
          log.error("Could not find the TestPlan!");
          System.exit(1);
        }
        if (((TestPlan) plan[0]).isSerialized())
        {
            serialized = true;
        }
        compileTree();
       
        /**
         * Notification of test listeners needs to happen after function replacement, but before
         * setting RunningVersion to true.
         */
        testListeners = new SearchByClass(TestListener.class);
        getTestTree().traverse(testListeners);
        log.info("About to call test listeners");
        Collection col = testListeners.getSearchResults();
        col.addAll(testList);
        testList=null;
        notifyTestListenersOfStart();
       
        getTestTree().traverse(new TurnElementsOn());
       
        List testLevelElements =
            new LinkedList(getTestTree().list(getTestTree().getArray()[0]));
        removeThreadGroups(testLevelElements);
        SearchByClass searcher = new SearchByClass(ThreadGroup.class);
       
        setMode();
        getTestTree().traverse(searcher);
        TestCompiler.initialize();
        //for each thread group, generate threads
        // hand each thread the sampler controller
        // and the listeners, and the timer
        JMeterThread[] threads;
        Iterator iter = searcher.getSearchResults().iterator();

        /*
         * Here's where the test really starts. Run a Full GC now: it's no
         * harm at all (just delays test start by a tiny amount) and
         * hitting one too early in the test can impair results for short
         * tests.
         */
        System.gc();
       
       
        notifier = new ListenerNotifier();
       
        schcdule_run = true;
        JMeterContextService.getContext().setSamplingStarted(true);
        int groupCount = 0;
        while (iter.hasNext())
        {
          groupCount++;
            ThreadGroup group = (ThreadGroup) iter.next();
      int numThreads = group.getNumThreads();
      boolean onErrorStopTest = group.getOnErrorStopTest();
      boolean onErrorStopThread = group.getOnErrorStopThread();
      String groupName = group.getName();
      int rampUp = group.getRampUp();
      float perThreadDelay = ((float) (rampUp * 1000) / (float) numThreads);
            threads = new JMeterThread[numThreads];
     
            log.info("Starting " + numThreads + " threads for group "+ groupName
                + ". Ramp up = "+ rampUp + ".");
           
      if (onErrorStopTest) {
        log.info("Test will stop on error");
      } else if (onErrorStopThread) {
        log.info("Thread will stop on error");
      } else {
        log.info("Continue on error");
      }

            for (int i = 0; running && i < threads.length; i++)
            {
                ListedHashTree threadGroupTree =
                    (ListedHashTree) searcher.getSubTree(group);
                threadGroupTree.add(group, testLevelElements);
                threads[i] =
                    new JMeterThread(
                        cloneTree(threadGroupTree),
                        this,
                        notifier);
                threads[i].setThreadNum(i);
                threads[i].setInitialContext(JMeterContextService.getContext());
                threads[i].setInitialDelay((int) (perThreadDelay * (float) i));
                String threadName = groupName + " " + groupCount + "-" + (i + 1);
                threads[i].setThreadName(threadName);

                scheduleThread(threads[i], group);
               
                // Set up variables for stop handling
                threads[i].setEngine(this);
        threads[i].setOnErrorStopTest(onErrorStopTest);
        threads[i].setOnErrorStopThread(onErrorStopThread);
       
                Thread newThread = new Thread(threads[i]);
                newThread.setName(threadName);
                allThreads.put(threads[i], newThread);
                allThreadNames.put(threadName,threads[i]);
                if (serialized
                    && !iter.hasNext()
                    && i == threads.length - 1) //last thread
                {
                    serialized = false;
                }
                newThread.start();
            }
            schcdule_run = false;
            if (serialized)
            {
                while (running && allThreads.size() > 0)
                {
                    try
                    {
                        Thread.sleep(1000);
                    }
                    catch (InterruptedException e)
                    {}
                }
            }
        }
    }

    /**
     * This will  schedule the time for the JMeterThread.
     *
     * @param thread
     * @param group
     */
    private void scheduleThread(JMeterThread thread, ThreadGroup group)
    {           
        //if true the Scheduler is enabled
        if (group.getScheduler())
        {
      //set the starttime for the Thread
          if (group.getDelay() > 0 ){// Duration is  in seconds
        thread.setStartTime(group.getDelay()*1000+(new Date().getTime()));
          } else {
        thread.setStartTime(group.getStartTime());
          }
           
      //set the endtime for the Thread
            if (group.getDuration() > 0){// Duration is  in seconds
        thread.setEndTime(group.getDuration()*1000+(thread.getStartTime()));
            } else {
        thread.setEndTime(group.getEndTime());
            }

            //Enables the scheduler
            thread.setScheduled(true);
        }
    }

    private boolean verifyThreadsStopped()
    {
      boolean stoppedAll=true;
        Iterator iter = new HashSet(allThreads.keySet()).iterator();
        while (iter.hasNext())
        {
            Thread t = (Thread) allThreads.get(iter.next());
            if (t != null && t.isAlive())
            {
                try
                {
                    t.join(WAIT_TO_DIE);
                }
                catch (InterruptedException e)
                {}
                if (t.isAlive())
                {
                  stoppedAll=false;
                    log.info("Thread won't die: " + t.getName());
                }
            }
        }
        return stoppedAll;
    }

    private void tellThreadsToStop()
    {
        Iterator iter = new HashSet(allThreads.keySet()).iterator();
        while (iter.hasNext())
        {
            JMeterThread item = (JMeterThread) iter.next();
            item.stop();
            Thread t = (Thread) allThreads.get(item);
            if (t != null)
            {
                t.interrupt();
            }
            else
            {
                log.warn("Lost thread: " + item.getThreadName());
                allThreads.remove(item);
            }
        }
    }
   
  private void stopAllThreads()
  {
    Iterator iter = new HashSet(allThreads.keySet()).iterator();
    while (iter.hasNext())
    {
      JMeterThread item = (JMeterThread) iter.next();
      item.stop();
    }
  }

    // Remote exit
    public void exit()
    {
      // Needs to be run in a separate thread to allow RMI call to return OK
    Thread t = new Thread(){
      public void run(){
        //log.info("Pausing");
        try
                {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e)
                {
                }
        log.info("Bye");
        System.exit(0);
      };
    };
    log.info("Starting Closedown");
    t.start();
    }
}
TOP

Related Classes of org.apache.jmeter.engine.StandardJMeterEngine$StopTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.