package org.apache.jmeter.timers;

import java.io.Serializable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.engine.event.LoopIterationListener;
import org.apache.jmeter.samplers.Interruptible;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;

public class InterruptTimer extends AbstractTestElement implements Timer, Serializable, LoopIterationListener {

    private static final long serialVersionUID = 1L;

    private static final Logger LOG = LoggingManager.getLoggerForClass();

    private static final String TIMEOUT = "InterruptTimer.timeout"; //$NON-NLS-1$

    private long timeout = 0;

    private JMeterContext context;

    private ScheduledFuture<?> future;
    
    private ScheduledExecutorService tpool;
    
    private final boolean debug;

    /**
     * No-arg constructor.
     */
    public InterruptTimer() {
        debug = LOG.isDebugEnabled(); // TODO is this the best place for this? 
    }

    /**
     * Set the timeout for this timer.
     * @param timeout The timeout for this timer
     */
    public void setTimeout(String timeout) {
        setProperty(TIMEOUT, timeout);
    }

    /**
     * Get the timeout value for display.
     *
     * @return the timeout value for display.
     */
    public String getTimeout() {
        return getPropertyAsString(TIMEOUT);
    }

    /**
     * Retrieve the delay to use during test execution.
     * This is called just before starting a sampler.
     * It is used to schedule future task to interrupt the sampler.
     * 
     * @return Always returns zero, because this timer does not wait
     */
    @Override
    public long delay() {
        if (future != null) {
            if (!future.isDone()) {
                boolean cancelled = future.cancel(false);
                if (debug) {
                    LOG.debug("Cancelled the task:" + future + " with result " + cancelled);
                }
            }
            future = null;
        }
        if (timeout <= 0) {
            return 0;
        }
        final Sampler samp = context.getCurrentSampler();
        if (!(samp instanceof Interruptible)) {
            // Log this?
            return 0;
        }
        final Interruptible sampler = (Interruptible) samp;
        Runnable run=new Runnable() {
            public void run() {
                  boolean interrupted = sampler.interrupt();
                  if (interrupted) {
                      LOG.warn("The sampler " + samp.getName() + " was interrupted.");
                  }
            }
        };
        // schedule the interrupt to occur 
        future = tpool.schedule(run, timeout, TimeUnit.MILLISECONDS);
        return 0;
    }

    /**
     * Provide a description of this timer class.
     *
     * @return the description of this timer class.
     */
    @Override
    public String toString() {
        return JMeterUtils.getResString("interrupt_timer_memo"); //$NON-NLS-1$
    }

    /**
     * Gain access to any variables that have been defined.
     *
     * @see LoopIterationListener#iterationStart(LoopIterationEvent)
     */
    @Override
    public void iterationStart(LoopIterationEvent event) {
        timeout = getPropertyAsLong(TIMEOUT);
        context = JMeterContextService.getContext(); // TODO is this called from the correct thread?
        tpool = Executors.newScheduledThreadPool(1); // ditto
    }
}

@@ -195,16 +195,59 @@
 Future;%0A
+import java.util.concurrent.ThreadFactory;%0A
 import j
@@ -542,24 +542,74 @@
 estElement;%0A
+import org.apache.jmeter.testelement.TestElement;%0A
 import org.a
@@ -1411,24 +1411,105 @@
 ptTimer() %7B%0A
+//        LOG.setPriority(org.apache.log.Priority.DEBUG); // for local debugging%0A
         debu
@@ -2281,24 +2281,103 @@
 g delay() %7B%0A
+        if (debug) %7B%0A            LOG.debug(whoAmI(%22delay()%22, this));%0A        %7D%0A
         if (
@@ -3162,17 +3162,28 @@
 G.warn(%22
-T
+Interruped t
 he sampl
@@ -3193,135 +3193,406 @@
 %22 + 
-samp.getName() + %22 was interrupted.%22);%0A                  %7D%0A            %7D%0A        %7D;%0A        // schedule the interrupt to occur 
+getInfo(samp));%0A                  %7D else %7B%0A                      if (debug) %7B%0A                          LOG.debug(%22Did not interrupt the sampler %22 + getInfo(samp));                          %0A                      %7D%0A                  %7D%0A            %7D%0A        %7D;%0A        // schedule the interrupt to occur %0A        if (debug) %7B%0A            LOG.debug(%22Scheduling timer for %22 + getInfo(samp));%0A        %7D
 %0A   
@@ -4160,24 +4160,112 @@
 nt event) %7B%0A
+        if (debug) %7B%0A            LOG.debug(whoAmI(%22iterationStart()%22, this));%0A        %7D%0A
         time
@@ -4449,18 +4449,17 @@
 adPool(1
-);
+,
  // ditt
@@ -4460,16 +4460,543 @@
 / ditto%0A
+            new ThreadFactory() %7B%0A                public Thread newThread(Runnable r) %7B%0A                    Thread t = Executors.defaultThreadFactory().newThread(r);%0A                    t.setDaemon(true);%0A                    return t;%0A                %7D%0A            %7D);%0A    %7D%0A%0A    private String whoAmI(String id, TestElement o) %7B%0A        return id + %22 @%22 + System.identityHashCode(o)+ %22 '%22+ o.getName() + %22'%22;         %0A    %7D%0A%0A    private String getInfo(TestElement o) %7B%0A        return whoAmI(o.getClass().getSimpleName(), o); %0A
     %7D%0A%7D%0A

Add interrupt Timer Ensure threads are created as daemons Add some extra debug info Bugzilla Id: 58299