/*
* 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 net.grinder;
import net.grinder.console.common.ErrorQueue;
import net.grinder.console.common.Resources;
import net.grinder.console.communication.AgentProcessControlImplementation;
import net.grinder.console.communication.ConsoleCommunication;
import net.grinder.console.communication.ConsoleCommunicationImplementationEx;
import net.grinder.console.model.ConsoleProperties;
import net.grinder.engine.console.ErrorHandlerImplementation;
import net.grinder.util.StandardTimeAuthority;
import net.grinder.util.thread.Condition;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.behaviors.Caching;
import org.slf4j.Logger;
import java.util.Timer;
import static org.ngrinder.common.util.ExceptionUtils.processException;
import static org.ngrinder.common.util.NoOp.noOp;
/**
* Agent Controller which controls agent behavior. This class is subject to synchronized. So if you
* want to daemon, please refer {@link AgentControllerServerDaemon}
*
* @author JunHo Yoon
* @since 3.0
*/
public class AgentControllerServer {
private DefaultPicoContainer m_container;
private Timer m_timer;
private boolean m_shutdown = false;
private final Condition m_eventSyncCondition;
/**
* Constructor.
*
* @param resources message resource
* @param logger logger
* @param properties {@link ConsoleProperties}
* @param eventSyncCondition event synchronized condition to synchronize server stop phase.
*/
public AgentControllerServer(Resources resources, Logger logger, ConsoleProperties properties,
Condition eventSyncCondition) {
m_eventSyncCondition = eventSyncCondition;
m_container = new DefaultPicoContainer(new Caching());
m_container.addComponent(logger);
m_container.addComponent(resources);
m_container.addComponent(properties);
m_container.addComponent(new StandardTimeAuthority());
m_container.addComponent(ConsoleCommunicationImplementationEx.class);
m_container.addComponent(AgentProcessControlImplementation.class);
m_timer = new Timer(true);
m_container.addComponent(m_timer);
// m_container.addComponent(WireEnhancedProcessReportMessage.class);
m_container.addComponent(ErrorQueue.class);
ErrorQueue errorQueue = m_container.getComponent(ErrorQueue.class);
errorQueue.setErrorHandler(new ErrorHandlerImplementation(logger));
}
/**
* Run agent controller in synchronized way.
*/
public void run() {
if (m_shutdown) {
throw processException("The console can not be run because it's already shutdown");
}
m_container.start();
m_container.getComponent(AgentProcessControlImplementation.class);
ConsoleCommunication communication = m_container.getComponent(ConsoleCommunication.class);
synchronized (m_eventSyncCondition) {
// Now ready to work
m_eventSyncCondition.notifyAll();
}
// CHECKSTYLE:OFF
while (communication.processOneMessage()) {
noOp();
// Fall through
// Process until communication is shut down.
}
}
/**
* Shut down the console.
*
*/
public void shutdown() {
m_shutdown = true;
m_container.getComponent(ConsoleCommunication.class).shutdown();
try {
m_timer.cancel();
} catch (Exception e) {
// Fall through
noOp();
}
if (m_container.getLifecycleState().isStarted()) {
m_container.stop();
}
}
/**
* Get internal component.
*
* @param componentType component type class
* @param <T> component type
* @return component
*/
public <T> T getComponent(Class<T> componentType) {
return m_container.getComponent(componentType);
}
}