<commit_before>/* 
 * 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 org.ngrinder;

import static org.ngrinder.common.util.NoOp.noOp;
import static org.ngrinder.common.util.Preconditions.checkNotNull;

import java.io.File;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;

import net.grinder.AgentControllerDaemon;
import net.grinder.communication.AgentControllerCommunicationDefauts;
import net.grinder.util.NetworkUtil;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.hyperic.sigar.ProcState;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.ngrinder.infra.AgentConfig;
import org.ngrinder.jnlp.JNLPLoader;
import org.ngrinder.monitor.MonitorConstants;
import org.ngrinder.monitor.agent.AgentMonitorServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.joran.spi.JoranException;

/**
 * Main class to start agent or monitor.
 * 
 * @author Mavlarn
 * @author <NAME>
 * @since 3.0
 */
public class NGrinderStarter {

	private static final Logger LOG = LoggerFactory.getLogger(NGrinderStarter.class);

	private AgentConfig agentConfig;

	private AgentControllerDaemon agentController;

	private ReconfigurableURLClassLoader classLoader;

	private File jnlpLibPath;

	private static final String LOCAL_NATIVE_PATH = "./native_lib";
	
	private boolean isWebStart = false;

	private JNLPLoader jnlpLoader;
	
	/**
	 * Constructor.
	 */
	public NGrinderStarter() {
	
		// Check agent start mode
		isWebStart =  BooleanUtils.toBoolean(System.getProperty("start.webstart", "false"));

		
		if (!isValidCurrentDirectory() && !isWebStart) {
			staticPrintHelpAndExit("nGrinder agent should start in the folder which nGrinder agent exists.");
		}
		agentConfig = new AgentConfig();
		agentConfig.init();
		// Configure log.
		Boolean verboseMode = agentConfig.getPropertyBoolean("verbose", false);
		File logDirectory = agentConfig.getHome().getLogDirectory();
		configureLogging(verboseMode, logDirectory);
		addClassPath();
		addLibarayPath();
	}

	private void addCustomClassLoader() {
		URL[] urLs = ((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs();
		this.classLoader = new ReconfigurableURLClassLoader(urLs);
		Thread.currentThread().setContextClassLoader(this.classLoader);
	}

	/*
	 * get the start mode, "agent" or "monitor". If it is not set in configuration, it will return
	 * "agent".
	 */
	public String getStartMode() {
		return agentConfig.getAgentProperties().getProperty("start.mode", "agent");
	}

	/**
	 * Get agent version.
	 * 
	 * @return version string
	 */
	public String getVersion() {
		return agentConfig.getInternalProperty("ngrinder.version", "UNKNOWN");
	}

	/**
	 * Start the performance monitor.
	 */
	public void startMonitor() {
		LOG.info("**************************");
		LOG.info("* Start nGrinder Monitor *");
		LOG.info("**************************");
		LOG.info("* Colllect SYSTEM data. **");

		MonitorConstants.init(agentConfig);

		try {

			String localHostAddress = NetworkUtil.getLocalHostAddress();
			System.setProperty("java.rmi.server.hostname", localHostAddress);
			AgentMonitorServer.getInstance().init(agentConfig.getHome().getDirectory());
			AgentMonitorServer.getInstance().start();
		} catch (Exception e) {
			LOG.error("ERROR: {}", e.getMessage());
			printHelpAndExit("Error while starting Monitor", e);
		}
	}

	/**
	 * Stop monitors.
	 */
	public void stopMonitor() {
		AgentMonitorServer.getInstance().stop();
	}

	/**
	 * Start ngrinder agent.
	 * 
	 * @param controllerIp
	 *            controllerIp;
	 */
	public void startAgent(String controllerIp) {
		LOG.info("***************************************************");
		LOG.info(" Start nGrinder Agent ...");
		String consoleIP = StringUtils.isNotEmpty(controllerIp) ? controllerIp : agentConfig.getAgentProperties()
						.getProperty("agent.console.ip", "127.0.0.1");

		if (!NetworkUtil.isValidIP(consoleIP)) {
			LOG.error("Hey!! {} does not seems like IP. Try to resolve the ip by {}.", consoleIP, consoleIP);
			InetAddress byName;
			try {
				byName = InetAddress.getByName(consoleIP);
				consoleIP = byName.getHostAddress();
				agentConfig.getAgentProperties().setProperty("agent.console.ip", consoleIP);
				LOG.info("Console IP is resolved as  {}.", consoleIP);
			} catch (UnknownHostException e) {
				consoleIP = "127.0.0.1";
				LOG.info("Console IP   resolution is failed. Use 127.0.0.1 instead.");
			} finally {
				agentConfig.getAgentProperties().setProperty("agent.console.ip", consoleIP);
			}

		}
		int consolePort = agentConfig.getAgentProperties().getPropertyInt("agent.console.port",
						AgentControllerCommunicationDefauts.DEFAULT_AGENT_CONTROLLER_SERVER_PORT);
		String region = agentConfig.getAgentProperties().getProperty("agent.region", "");
		LOG.info("with console: {}:{}", consoleIP, consolePort);
		boolean serverMode = agentConfig.getPropertyBoolean("agent.servermode", false);
		if (!serverMode) {
			LOG.info("JVM server mode is disabled. If you turn on ngrinder.servermode in agent.conf."
							+ " It will provide the better agent performance.");
		}

		try {
			String localHostAddress = NetworkUtil.getLocalHostAddress();
			System.setProperty("java.rmi.server.hostname", localHostAddress);
			agentController = new AgentControllerDaemon(localHostAddress);
			agentController.getAgentController().setAgentConfig(agentConfig);
			agentController.setRegion(region);
			agentController.setAgentConfig(agentConfig);
			agentController.run(consoleIP, consolePort);
		} catch (Exception e) {
			LOG.error("ERROR: {}", e.getMessage());
			printHelpAndExit("Error while starting Agent", e);
		}
	}

	/**
	 * stop the ngrinder agent.
	 */
	public void stopAgent() {
		LOG.info("Stop nGrinder agent!");
		agentController.shutdown();
	}

	private void addLibarayPath() {
		String property = StringUtils.trimToEmpty(System.getProperty("java.library.path"));
		String nativePath = isWebStart ? jnlpLibPath.getAbsolutePath() : LOCAL_NATIVE_PATH;
		System.setProperty("java.library.path", property + File.pathSeparator + nativePath);
		LOG.info("java.library.path : {} ", System.getProperty("java.library.path"));
	}

	/**
	 * Get jar file list.
	 * 
	 * @return jar file collection
	 */
	protected Collection<File> getJarFileList() {

		ArrayList<File> fileString = new ArrayList<File>();
		if (isWebStart) {
			jnlpLibPath = new File(agentConfig.getHome().getDirectory(), "jnlp_res");

			try {
				Class<?> loader = Class.forName("org.ngrinder.jnlp.impl.JNLPLoaderImpl");
				jnlpLoader = (JNLPLoader) loader.newInstance();
				if (!jnlpLoader.isWebStartPossible())
					staticPrintHelpAndExit("Sorry,Your JDK is not met nGrinder Agent request, "
							+ "\n Please secure yours is Sun/Oracle JDK! ");

				fileString.addAll(jnlpLoader.resolveRemoteJars(jnlpLibPath));
			} catch (Exception e) {
				staticPrintHelpAndExit("Error occurs while getting Jar file from Service !", e);
			}

		} else {
			File libFolder = new File(".", "lib").getAbsoluteFile();
			if (!libFolder.exists()) {
				printHelpAndExit("lib path (" + libFolder.getAbsolutePath() + ") does not exist");
			}
			String[] exts = new String[] { "jar" };
			fileString.addAll(FileUtils.listFiles(libFolder, exts, false));
		}

		return fileString;
	}

	/**
	 * Add class path.<commit_msg>[NOBTS] Fix message.<commit_after>/* 
 * 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 org.ngrinder;

import static org.ngrinder.common.util.NoOp.noOp;
import static org.ngrinder.common.util.Preconditions.checkNotNull;

import java.io.File;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;

import net.grinder.AgentControllerDaemon;
import net.grinder.communication.AgentControllerCommunicationDefauts;
import net.grinder.util.NetworkUtil;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.hyperic.sigar.ProcState;
import org.hyperic.sigar.Sigar;
import org.hyperic.sigar.SigarException;
import org.ngrinder.infra.AgentConfig;
import org.ngrinder.jnlp.JNLPLoader;
import org.ngrinder.monitor.MonitorConstants;
import org.ngrinder.monitor.agent.AgentMonitorServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.joran.spi.JoranException;

/**
 * Main class to start agent or monitor.
 * 
 * @author Mavlarn
 * @author <NAME>
 * @since 3.0
 */
public class NGrinderStarter {

	private static final Logger LOG = LoggerFactory.getLogger(NGrinderStarter.class);

	private AgentConfig agentConfig;

	private AgentControllerDaemon agentController;

	private ReconfigurableURLClassLoader classLoader;

	private File jnlpLibPath;

	private static final String LOCAL_NATIVE_PATH = "./native_lib";
	
	private boolean isWebStart = false;

	private JNLPLoader jnlpLoader;
	
	/**
	 * Constructor.
	 */
	public NGrinderStarter() {
	
		// Check agent start mode
		isWebStart =  BooleanUtils.toBoolean(System.getProperty("start.webstart", "false"));

		
		if (!isValidCurrentDirectory() && !isWebStart) {
			staticPrintHelpAndExit("nGrinder agent should start in the folder which nGrinder agent exists.");
		}
		agentConfig = new AgentConfig();
		agentConfig.init();
		// Configure log.
		Boolean verboseMode = agentConfig.getPropertyBoolean("verbose", false);
		File logDirectory = agentConfig.getHome().getLogDirectory();
		configureLogging(verboseMode, logDirectory);
		addClassPath();
		addLibarayPath();
	}

	private void addCustomClassLoader() {
		URL[] urLs = ((URLClassLoader) Thread.currentThread().getContextClassLoader()).getURLs();
		this.classLoader = new ReconfigurableURLClassLoader(urLs);
		Thread.currentThread().setContextClassLoader(this.classLoader);
	}

	/*
	 * get the start mode, "agent" or "monitor". If it is not set in configuration, it will return
	 * "agent".
	 */
	public String getStartMode() {
		return agentConfig.getAgentProperties().getProperty("start.mode", "agent");
	}

	/**
	 * Get agent version.
	 * 
	 * @return version string
	 */
	public String getVersion() {
		return agentConfig.getInternalProperty("ngrinder.version", "UNKNOWN");
	}

	/**
	 * Start the performance monitor.
	 */
	public void startMonitor() {
		LOG.info("**************************");
		LOG.info("* Start nGrinder Monitor *");
		LOG.info("**************************");
		LOG.info("* Colllect SYSTEM data. **");

		MonitorConstants.init(agentConfig);

		try {

			String localHostAddress = NetworkUtil.getLocalHostAddress();
			System.setProperty("java.rmi.server.hostname", localHostAddress);
			AgentMonitorServer.getInstance().init(agentConfig.getHome().getDirectory());
			AgentMonitorServer.getInstance().start();
		} catch (Exception e) {
			LOG.error("ERROR: {}", e.getMessage());
			printHelpAndExit("Error while starting Monitor", e);
		}
	}

	/**
	 * Stop monitors.
	 */
	public void stopMonitor() {
		AgentMonitorServer.getInstance().stop();
	}

	/**
	 * Start ngrinder agent.
	 * 
	 * @param controllerIp
	 *            controllerIp;
	 */
	public void startAgent(String controllerIp) {
		LOG.info("***************************************************");
		LOG.info(" Start nGrinder Agent ...");
		String consoleIP = StringUtils.isNotEmpty(controllerIp) ? controllerIp : agentConfig.getAgentProperties()
						.getProperty("agent.console.ip", "127.0.0.1");

		if (!NetworkUtil.isValidIP(consoleIP)) {
			LOG.error("Hey!! {} does not seems like IP. Try to resolve the ip by {}.", consoleIP, consoleIP);
			InetAddress byName;
			try {
				byName = InetAddress.getByName(consoleIP);
				consoleIP = byName.getHostAddress();
				agentConfig.getAgentProperties().setProperty("agent.console.ip", consoleIP);
				LOG.info("Console IP is resolved as  {}.", consoleIP);
			} catch (UnknownHostException e) {
				consoleIP = "127.0.0.1";
				LOG.info("Console IP   resolution is failed. Use 127.0.0.1 instead.");
			} finally {
				agentConfig.getAgentProperties().setProperty("agent.console.ip", consoleIP);
			}

		}
		int consolePort = agentConfig.getAgentProperties().getPropertyInt("agent.console.port",
						AgentControllerCommunicationDefauts.DEFAULT_AGENT_CONTROLLER_SERVER_PORT);
		String region = agentConfig.getAgentProperties().getProperty("agent.region", "");
		LOG.info("with console: {}:{}", consoleIP, consolePort);
		boolean serverMode = agentConfig.getPropertyBoolean("agent.servermode", false);
		if (!serverMode) {
			LOG.info("JVM server mode is disabled. If you turn on ngrinder.servermode in agent.conf."
							+ " It will provide the better agent performance.");
		}

		try {
			String localHostAddress = NetworkUtil.getLocalHostAddress();
			System.setProperty("java.rmi.server.hostname", localHostAddress);
			agentController = new AgentControllerDaemon(localHostAddress);
			agentController.getAgentController().setAgentConfig(agentConfig);
			agentController.setRegion(region);
			agentController.setAgentConfig(agentConfig);
			agentController.run(consoleIP, consolePort);
		} catch (Exception e) {
			LOG.error("ERROR: {}", e.getMessage());
			printHelpAndExit("Error while starting Agent", e);
		}
	}

	/**
	 * stop the ngrinder agent.
	 */
	public void stopAgent() {
		LOG.info("Stop nGrinder agent!");
		agentController.shutdown();
	}

	private void addLibarayPath() {
		String property = StringUtils.trimToEmpty(System.getProperty("java.library.path"));
		String nativePath = isWebStart ? jnlpLibPath.getAbsolutePath() : LOCAL_NATIVE_PATH;
		System.setProperty("java.library.path", property + File.pathSeparator + nativePath);
		LOG.info("java.library.path : {} ", System.getProperty("java.library.path"));
	}

	/**
	 * Get jar file list.
	 * 
	 * @return jar file collection
	 */
	protected Collection<File> getJarFileList() {

		ArrayList<File> fileString = new ArrayList<File>();
		if (isWebStart) {
			jnlpLibPath = new File(agentConfig.getHome().getDirectory(), "jnlp_res");

			try {
				Class<?> loader = Class.forName("org.ngrinder.jnlp.impl.JNLPLoaderImpl");
				jnlpLoader = (JNLPLoader) loader.newInstance();
				if (!jnlpLoader.isWebStartPossible())
					staticPrintHelpAndExit("Sorry, nGrinder agent can not run on your JDK, "
							+ "\n Please install Oracle JDK! ");

				fileString.addAll(jnlpLoader.resolveRemoteJars(jnlpLibPath));
			} catch (Exception e) {
				staticPrintHelpAndExit("Error occurs while getting Jar file from Service !", e);
			}

		} else {
			File libFolder = new File(".", "lib").getAbsoluteFile();
			if (!libFolder.exists()) {
				printHelpAndExit("lib path (" + libFolder.getAbsolutePath() + ") does not exist");
			}
			String[] exts = new String[] { "jar" };
			fileString.addAll(FileUtils.listFiles(libFolder, exts, false));
		}

		return fileString;
	}

	/**
	 * Add class path.
{'fraction_non_alphanumeric': 0.13646341463414635, 'fraction_numerical': 0.0031707317073170734, 'mean_word_length': 4.574779061862678, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3434405', 'n_tokens_mistral': 5365, 'n_tokens_neox': 4861, 'n_words': 1120}