net.grinder.console.ConsoleFoundationEx.java Source code

Java tutorial

Introduction

Here is the source code for net.grinder.console.ConsoleFoundationEx.java

Source

// 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.console;

import net.grinder.common.GrinderException;
import net.grinder.communication.MessageDispatchRegistry;
import net.grinder.communication.MessageDispatchRegistry.AbstractHandler;
import net.grinder.console.common.ErrorQueue;
import net.grinder.console.common.Resources;
import net.grinder.console.communication.ConsoleCommunication;
import net.grinder.console.communication.ConsoleCommunicationImplementationEx;
import net.grinder.console.communication.DistributionControlImplementation;
import net.grinder.console.communication.ProcessControlImplementation;
import net.grinder.console.communication.server.DispatchClientCommands;
import net.grinder.console.distribution.FileDistributionImplementation;
import net.grinder.console.distribution.WireFileDistribution;
import net.grinder.console.model.*;
import net.grinder.console.synchronisation.WireDistributedBarriers;
import net.grinder.engine.console.ErrorHandlerImplementation;
import net.grinder.messages.console.RegisterExpressionViewMessage;
import net.grinder.messages.console.RegisterTestsMessage;
import net.grinder.messages.console.ReportStatisticsMessage;
import net.grinder.statistics.StatisticsServicesImplementation;
import net.grinder.util.StandardTimeAuthority;
import net.grinder.util.thread.Condition;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.Parameter;
import org.picocontainer.behaviors.Caching;
import org.picocontainer.parameters.ComponentParameter;
import org.picocontainer.parameters.ConstantParameter;
import org.slf4j.Logger;

import java.util.Timer;

import static org.ngrinder.common.util.ExceptionUtils.processException;
import static org.ngrinder.common.util.NoOp.noOp;

/**
 * Extension of {@link ConsoleFoundation} for nGrinder use.
 *
 * @author Grinder Developers.
 * @author JunHo Yoon (modified for nGrinder)
 * @since 3.0
 */
public class ConsoleFoundationEx {

    private final MutablePicoContainer m_container;
    private final Timer m_timer;
    private boolean m_shutdown = false;

    private final Condition m_eventSyncCondition;

    /**
     * Constructor. Allows properties to be specified.
     * 
     * @param resources      Console resources
     * @param logger      Logger.
     * @param properties   The properties.
     * @param eventSyncCondition   event synchronization condition.
     * @exception GrinderException   occurs If an error occurs.
     */
    public ConsoleFoundationEx(Resources resources, Logger logger, ConsoleProperties properties,
            ConsoleCommunicationSetting consoleCommunicationSetting, Condition eventSyncCondition)
            throws GrinderException {
        m_eventSyncCondition = eventSyncCondition;
        m_container = new DefaultPicoContainer(new Caching());
        m_container.addComponent(logger);
        m_container.addComponent(resources);
        m_container.addComponent(properties);
        m_container.addComponent(StatisticsServicesImplementation.getInstance());
        m_container.addComponent(new StandardTimeAuthority());
        m_container.addComponent(consoleCommunicationSetting);

        m_container.addComponent(SampleModelImplementationEx.class);
        m_container.addComponent(SampleModelViewsImplementation.class);
        m_container.addComponent(ConsoleCommunicationImplementationEx.class);
        m_container.addComponent(DistributionControlImplementation.class);
        m_container.addComponent(ProcessControlImplementation.class);
        m_timer = new Timer(true);
        m_container.addComponent(m_timer);

        //noinspection RedundantArrayCreation
        m_container.addComponent(FileDistributionImplementation.class, FileDistributionImplementation.class,
                new Parameter[] { new ComponentParameter(DistributionControlImplementation.class),
                        new ComponentParameter(ProcessControlImplementation.class),
                        new ConstantParameter(properties.getDistributionDirectory()),
                        new ConstantParameter(properties.getDistributionFileFilterPattern()), });

        m_container.addComponent(DispatchClientCommands.class);
        m_container.addComponent(WireFileDistribution.class);
        m_container.addComponent(WireMessageDispatch.class);
        m_container.addComponent(WireDistributedBarriers.class);
        m_container.addComponent(ErrorQueue.class);

        ErrorQueue errorQueue = m_container.getComponent(ErrorQueue.class);
        errorQueue.setErrorHandler(new ErrorHandlerImplementation(logger));
    }

    /**
     * Get the component of the given type.
     * 
     * @param <T>   component type
     * @param componentType   component type class
     * @return component
     */
    public <T> T getComponent(Class<T> componentType) {
        return m_container.getComponent(componentType);
    }

    /**
     * Shut down the console.
     * 
     */
    public void shutdown() {
        m_shutdown = true;
        m_container.getComponent(ConsoleCommunication.class).shutdown();
        try {
            m_timer.cancel();
        } catch (Exception e) {
            noOp();
        }
        if (m_container.getLifecycleState().isStarted()) {
            m_container.stop();
        }
    }

    private String getConsoleInfo() {
        ConsoleProperties consoleProperties = m_container.getComponent(ConsoleProperties.class);
        return StringUtils.defaultIfBlank(consoleProperties.getConsoleHost(), "localhost") + ":"
                + consoleProperties.getConsolePort();
    }

    /**
     * Console message event loop.
     * 
     * Dispatches communication messages appropriately. Blocks until we are {@link #shutdown()}.
     */
    public void run() {
        if (m_shutdown) {
            throw processException("console can not run because it's shutdowned");
        }
        m_container.start();
        ConsoleCommunication communication = m_container.getComponent(ConsoleCommunication.class);
        // Need to request components, or they won't be instantiated.
        m_container.getComponent(WireMessageDispatch.class);
        m_container.getComponent(WireFileDistribution.class);
        m_container.getComponent(WireDistributedBarriers.class);
        m_container.getComponent(Logger.class).info("console {} has been started", getConsoleInfo());
        synchronized (m_eventSyncCondition) {
            m_eventSyncCondition.notifyAll();
        }
        while (communication.processOneMessage()) {
            // Process until communication is shut down.
            noOp();
        }

    }

    /**
     * @return the m_container
     */
    public MutablePicoContainer getContainer() {
        return m_container;
    }

    /**
     * Factory that wires up the message dispatch.
     * 
     * <p>
     * Must be public for PicoContainer.
     * </p>
     * 
     * @see WireFileDistribution
     */
    public static class WireMessageDispatch {

        /**
         * Constructor.
         * 
         * @param communication   Console communication.
         * @param model         Console sample model.
         * @param sampleModelViews   Console sample model views
         * @param dispatchClientCommands   Client command dispatcher.
         */
        public WireMessageDispatch(ConsoleCommunication communication, final SampleModel model,
                final SampleModelViews sampleModelViews, DispatchClientCommands dispatchClientCommands) {

            final MessageDispatchRegistry messageDispatchRegistry = communication.getMessageDispatchRegistry();

            messageDispatchRegistry.set(RegisterTestsMessage.class, new AbstractHandler<RegisterTestsMessage>() {
                public void handle(RegisterTestsMessage message) {
                    model.registerTests(message.getTests());
                }
            });

            messageDispatchRegistry.set(ReportStatisticsMessage.class,
                    new AbstractHandler<ReportStatisticsMessage>() {
                        public void handle(ReportStatisticsMessage message) {
                            model.addTestReport(message.getStatisticsDelta());
                        }
                    });

            messageDispatchRegistry.set(RegisterExpressionViewMessage.class,
                    new AbstractHandler<RegisterExpressionViewMessage>() {
                        public void handle(RegisterExpressionViewMessage message) {
                            sampleModelViews.registerStatisticExpression(message.getExpressionView());
                        }
                    });

            dispatchClientCommands.registerMessageHandlers(messageDispatchRegistry);
        }
    }
}