Package net.grinder.engine.process

Source Code of net.grinder.engine.process.ThreadContextImplementation$DispatchContextStack

// Copyright (C) 2000 Paco Gomez
// Copyright (C) 2000 - 2012 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package net.grinder.engine.process;

import java.util.ArrayList;
import java.util.List;

import net.grinder.common.GrinderProperties;
import net.grinder.common.SSLContextFactory;
import net.grinder.common.SkeletonThreadLifeCycleListener;
import net.grinder.common.Test;
import net.grinder.common.ThreadLifeCycleListener;
import net.grinder.engine.common.EngineException;
import net.grinder.engine.process.DispatchContext.DispatchStateException;
import net.grinder.script.Statistics.StatisticsForTest;
import net.grinder.statistics.StatisticsServices;
import net.grinder.statistics.StatisticsSet;
import net.grinder.util.ListenerSupport;
import net.grinder.util.ListenerSupport.Informer;

import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;

/**
* Package scope.
*
* @author Philip Aston
*/
final class ThreadContextImplementation implements ThreadContext {

  private final ListenerSupport<ThreadLifeCycleListener> m_threadLifeCycleListeners = new ListenerSupport<ThreadLifeCycleListener>();

  private final DispatchContextStack m_dispatchContextStack = new DispatchContextStack();

  private final int m_threadNumber;
  private final Marker m_threadMarker;
  private final DispatchResultReporter m_dispatchResultReporter;

  private SSLContextFactory m_sslContextFactory;

  private boolean m_delayReports;

  private DispatchContext m_pendingDispatchContext;

  private StatisticsForTest m_statisticsForLastTest;

  private Marker m_runMarker;
  private int m_runNumber = -1;

  private Marker m_testMarker;

  private volatile boolean m_shutdown;
  private boolean m_shutdownReported;

  public ThreadContextImplementation(GrinderProperties properties,
      StatisticsServices statisticsServices, int threadNumber,
      Logger dataLogger) throws EngineException {

    m_threadNumber = threadNumber;
    m_threadMarker = MarkerFactory.getMarker("thread-" + threadNumber);

    // Undocumented property. Added so Tom Barnes can investigate overhead
    // of data logging.
    if (properties.getBoolean("grinder.logData", true)) {
      final ThreadDataLogger threadDataLogger = new ThreadDataLogger(
          dataLogger, statisticsServices.getDetailStatisticsView()
              .getExpressionViews(), m_threadNumber);

      m_dispatchResultReporter = new DispatchResultReporter() {
        public void report(Test test, long startTime,
            StatisticsSet statistics) {
          threadDataLogger.report(getRunNumber(), test, startTime,
              statistics);
        }
      };
    } else {
      m_dispatchResultReporter = new DispatchResultReporter() {
        public void report(Test test, long startTime,
            StatisticsSet statistics) {
          // Null reporter.
        }
      };
    }

    registerThreadLifeCycleListener(new SkeletonThreadLifeCycleListener() {
      public void endRun() {
        reportPendingDispatchContext();
      }
    });
  }

  public int getThreadNumber() {
    return m_threadNumber;
  }

  public int getRunNumber() {
    return m_runNumber;
  }

  @Override
  public void setCurrentRunNumber(int run) {
    if (m_runMarker != null) {
      m_threadMarker.remove(m_runMarker);
      MarkerFactory.getIMarkerFactory().detachMarker(
          m_runMarker.getName());
    }

    if (run != -1) {
      m_runMarker = MarkerFactory.getMarker("run-" + run);
      m_threadMarker.add(m_runMarker);
    }

    m_runNumber = run;
  }

  /** Package scope for unit tests. */
  void setTestLogMarker(Marker marker) {
    if (m_testMarker != null) {
      m_threadMarker.remove(m_testMarker);
    }

    m_testMarker = marker;

    if (marker != null) {
      m_threadMarker.add(marker);
    }
  }

  public SSLContextFactory getThreadSSLContextFactory() {
    return m_sslContextFactory;
  }

  public void setThreadSSLContextFactory(SSLContextFactory sslContextFactory) {
    m_sslContextFactory = sslContextFactory;
  }

  public DispatchResultReporter getDispatchResultReporter() {
    return m_dispatchResultReporter;
  }

  public void registerThreadLifeCycleListener(ThreadLifeCycleListener listener) {
    m_threadLifeCycleListeners.add(listener);
  }

  public void removeThreadLifeCycleListener(ThreadLifeCycleListener listener) {
    m_threadLifeCycleListeners.remove(listener);
  }

  public void fireBeginThreadEvent() {
    m_threadLifeCycleListeners
        .apply(new Informer<ThreadLifeCycleListener>() {
          public void inform(ThreadLifeCycleListener l) {
            l.beginThread();
          }
        });
  }

  public void fireBeginRunEvent() {
    m_threadLifeCycleListeners
        .apply(new Informer<ThreadLifeCycleListener>() {
          public void inform(ThreadLifeCycleListener l) {
            l.beginRun();
          }
        });
  }

  public void fireEndRunEvent() {
    m_threadLifeCycleListeners
        .apply(new Informer<ThreadLifeCycleListener>() {
          public void inform(ThreadLifeCycleListener l) {
            l.endRun();
          }
        });
  }

  public void fireBeginShutdownEvent() {
    m_threadLifeCycleListeners
        .apply(new Informer<ThreadLifeCycleListener>() {
          public void inform(ThreadLifeCycleListener l) {
            l.beginShutdown();
          }
        });
  }

  public void fireEndThreadEvent() {
    m_threadLifeCycleListeners
        .apply(new Informer<ThreadLifeCycleListener>() {
          public void inform(ThreadLifeCycleListener l) {
            l.endThread();
          }
        });

  }

  public void pushDispatchContext(DispatchContext dispatchContext)
      throws ShutdownException {

    if (m_shutdown) {
      // As soon as we're shutdown, we disable the instrumentation. This
      // avoids reporting of misleading test failures.

      // We only throw ShutdownException from pushDispatchContext. A test
      // that
      // was in-flight at the time of shutdown will complete normally
      // unless
      // the thread attempts to start a nested test.
      m_shutdownReported = true;
      throw new ShutdownException("Thread has been shut down");
    }

    reportPendingDispatchContext();

    setTestLogMarker(dispatchContext.getLogMarker());

    final DispatchContext existingContext = m_dispatchContextStack
        .peekTop();

    if (existingContext != null) {
      existingContext.setHasNestedContexts();
    }

    m_dispatchContextStack.push(dispatchContext);
  }

  public void popDispatchContext() {
    if (m_shutdownReported) {
      return;
    }

    final DispatchContext dispatchContext = m_dispatchContextStack.pop();

    if (dispatchContext == null) {
      throw new AssertionError("DispatchContext stack unexpectedly empty");
    }

    final DispatchContext parentDispatchContext = m_dispatchContextStack
        .peekTop();

    if (parentDispatchContext != null) {
      parentDispatchContext.getPauseTimer().add(
          dispatchContext.getPauseTimer());
    }

    m_statisticsForLastTest = dispatchContext.getStatisticsForTest();

    // Flush any pending report created by an inner test.
    reportPendingDispatchContext();

    if (m_delayReports) {
      m_pendingDispatchContext = dispatchContext;
    } else {
      try {
        dispatchContext.report();
      } catch (DispatchStateException e) {
        throw new AssertionError(e);
      }
    }

    setTestLogMarker(null);
  }

  public StatisticsForTest getStatisticsForCurrentTest() {
    final DispatchContext dispatchContext = m_dispatchContextStack
        .peekTop();

    if (dispatchContext == null) {
      return null;
    }

    return dispatchContext.getStatisticsForTest();
  }

  public StatisticsForTest getStatisticsForLastTest() {
    return m_statisticsForLastTest;
  }

  public void setDelayReports(boolean b) {
    if (!b) {
      reportPendingDispatchContext();
    }

    m_delayReports = b;
  }

  public void reportPendingDispatchContext() {
    if (m_pendingDispatchContext != null) {
      try {
        m_pendingDispatchContext.report();
      } catch (DispatchStateException e) {
        throw new AssertionError(e);
      }

      m_pendingDispatchContext = null;
    }
  }

  public void pauseClock() {
    final DispatchContext dispatchContext = m_dispatchContextStack
        .peekTop();

    if (dispatchContext != null) {
      dispatchContext.getPauseTimer().start();
    }
  }

  public void resumeClock() {
    final DispatchContext dispatchContext = m_dispatchContextStack
        .peekTop();

    if (dispatchContext != null) {
      dispatchContext.getPauseTimer().stop();
    }
  }

  private static final class DispatchContextStack {
    private final List<DispatchContext> m_stack = new ArrayList<DispatchContext>();

    public void push(DispatchContext dispatchContext) {
      m_stack.add(dispatchContext);
    }

    public DispatchContext pop() {
      final int size = m_stack.size();

      if (size == 0) {
        return null;
      }

      return m_stack.remove(size - 1);
    }

    public DispatchContext peekTop() {
      final int size = m_stack.size();

      if (size == 0) {
        return null;
      }

      return m_stack.get(size - 1);
    }
  }

  public void shutdown() {
    MarkerFactory.getIMarkerFactory()
        .detachMarker(m_threadMarker.getName());
    m_shutdown = true;
  }

  @Override
  public Marker getLogMarker() {
    return m_threadMarker;
  }
}
TOP

Related Classes of net.grinder.engine.process.ThreadContextImplementation$DispatchContextStack

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.