/* * 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.common.GrinderException; import net.grinder.engine.agent.Agent; import net.grinder.util.ListenerHelper; import net.grinder.util.ListenerSupport; import net.grinder.util.ListenerSupport.Informer; import net.grinder.util.thread.Condition; import org.ngrinder.common.util.ThreadUtils; import org.ngrinder.infra.AgentConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.ngrinder.common.util.ExceptionUtils.processException; /** * This is daemon wrapper for agent controller. * * @author JunHo Yoon */ public class AgentControllerDaemon implements Agent { private static final int LOG_FREQUENCY = 5; private final AgentController agentController; private Thread thread; private final ListenerSupport<AgentControllerShutDownListener> m_listeners = ListenerHelper.create(); private boolean forceShutdown = false; // event synchronization for @SuppressWarnings("FieldCanBeLocal") private Condition m_eventSyncCondition = new Condition(); public static final Logger LOGGER = LoggerFactory.getLogger("agent controller daemon"); /** * Constructor. * * @param agentConfig agent config */ public AgentControllerDaemon(AgentConfig agentConfig) { try { agentController = new AgentController(m_eventSyncCondition, agentConfig); } catch (GrinderException e) { throw processException("Exception occurred while initiating the agent controller daemon", e); } } private long count = 0; public void run() { thread = new Thread(new Runnable() { public void run() { do { try { if (count++ % LOG_FREQUENCY == 0) { LOGGER.info("The agent controller daemon is started."); } getAgentController().run(); getListeners().apply(new Informer<AgentControllerShutDownListener>() { public void inform(AgentControllerShutDownListener listener) { listener.shutdownAgentController(); } }); } catch (Exception e) { LOGGER.info("Agent controller daemon is crashed. {}", e.getMessage()); LOGGER.debug("The error detail is ", e); } if (isForceShutdown()) { setForceShutdown(false); break; } ThreadUtils.sleep(GrinderConstants.AGENT_CONTROLLER_RETRY_INTERVAL); } while (true); } }, "Agent Controller Thread"); thread.start(); } /** * Agent controller shutdown listener class. * * @author JunHo Yoon */ public interface AgentControllerShutDownListener { /** * Method which will be called when agent controller. */ public void shutdownAgentController(); } public ListenerSupport<AgentControllerShutDownListener> getListeners() { return this.m_listeners; } /** * Shutdown agent controller. */ public void shutdown() { try { setForceShutdown(true); agentController.shutdown(); if (thread != null) { ThreadUtils.stopQuietly(thread, "Agent controller thread was not stopped. Stop by force."); thread = null; } } catch (Exception e) { throw new RuntimeException(e); } } public AgentController getAgentController() { return agentController; } private boolean isForceShutdown() { return forceShutdown; } private synchronized void setForceShutdown(boolean force) { this.forceShutdown = force; } }