package rocks.inspectit.server;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import rocks.inspectit.server.util.Converter;
import rocks.inspectit.shared.all.minlog.MinlogToSLF4JLogger;
import rocks.inspectit.shared.all.util.ResourcesPathResolver;
import rocks.inspectit.shared.all.version.VersionService;
import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J;
/**
* Main class of the Central Measurement Repository. The main method is used to start the
* application.
*
* @author Patrice Bouillet
*
*/
public final class CMR {
/**
* The logger of this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CMR.class);
/**
* Default name of the log file.
*/
public static final String DEFAULT_LOG_FILE_NAME = "logging-config.xml";
/**
* JVM property for the log file location.
*/
private static final String LOG_FILE_PROPERTY = "inspectit.logging.config";
/**
* The spring bean factory to get the registered beans.
*/
private static BeanFactory beanFactory; // NOPMD
/**
* startedAsService holds the value if CMR was started as a Windows Service.
*/
private static boolean startedAsService;
/**
* This class will start the Repository.
*/
private CMR() {
}
/**
* Pseudo main method of class.
*/
private static void startCMR() {
initLogger();
long startTime = System.nanoTime();
LOGGER.info("Central Measurement Repository is starting up!");
LOGGER.info("==============================================");
startRepository();
LOGGER.info("CMR started in " + Converter.nanoToMilliseconds(System.nanoTime() - startTime) + " ms");
}
/**
* This class will start the Repository.
*/
private static void startRepository() {
checkForCorrectJvmVersion();
LOGGER.info("Initializing Spring...");
BeanFactoryLocator beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance();
BeanFactoryReference beanFactoryReference = beanFactoryLocator.useBeanFactory("ctx");
beanFactory = beanFactoryReference.getFactory();
if (beanFactory instanceof ConfigurableApplicationContext) {
((ConfigurableApplicationContext) beanFactory).registerShutdownHook();
}
LOGGER.info("Spring successfully initialized");
if (LOGGER.isInfoEnabled()) {
VersionService versionService = (VersionService) getBeanFactory().getBean("versionService");
LOGGER.info("Starting CMR in version " + versionService.getVersionAsString()
+ ". Please note that inspectIT does not provide any guarantee on backwards compatibility. Only if the version match exactly we ensure that the components are compatible.");
}
}
/**
* This method checks if the JVM the CMR is started on is compatible.
*/
private static void checkForCorrectJvmVersion() {
String version = System.getProperty("java.version");
// searching for Oracle version pattern: 1.7.0_80 or unofficial builds from OpenJDK:
// 1.7.0-u80-unofficial
Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)\\.(\\d+)[_-]u?(\\d+)").matcher(version);
boolean correctVersion = true;
if (matcher.find() && (matcher.groupCount() >= 4)) {
try {
int majorFirst = Integer.parseInt(matcher.group(1));
int majorSecond = Integer.parseInt(matcher.group(2));
int minor = Integer.parseInt(matcher.group(3));
int update = Integer.parseInt(matcher.group(4));
if ((majorFirst != 1) || (majorSecond != 7) || (minor != 0)) {
correctVersion = false;
}
if ((update < 51) || (update > 80)) {
correctVersion = false;
}
} catch (NumberFormatException e) {
correctVersion = false;
}
} else {
correctVersion = false;
}
if (!correctVersion) {
LOGGER.warn("ATTENTION: The version of this JVM (" + version + ") is not compatible with the CMR! Please use the JVM that is provided with the installation!");
} else {
LOGGER.info("The version of this JVM (" + version + ") is compatible with the CMR.");
}
}
/**
* Start function. Needed by Procrun.
*
* @param args
* The arguments.
*/
public static void start(String[] args) {
startedAsService = true;
startCMR();
}
/**
* Stop function. Needed by Procrun.
*
* @param args
* The arguments.
*/
public static void stop(String[] args) {
System.exit(0);
}
/**
* Initializes the logger.
*/
private static void initLogger() {
LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(context);
context.reset();
InputStream is = null;
try {
// first check if it's supplied as parameter
String logFileLocation = System.getProperty(LOG_FILE_PROPERTY);
if (null != logFileLocation) {
Path logPath = Paths.get(logFileLocation).toAbsolutePath();
if (Files.exists(logPath)) {
is = Files.newInputStream(logPath, StandardOpenOption.READ);
}
}
// then fail to default if none is specified
if (null == is) {
Path logPath = ResourcesPathResolver.getResourceFile(DEFAULT_LOG_FILE_NAME).toPath().toAbsolutePath();
if (Files.exists(logPath)) {
is = Files.newInputStream(logPath, StandardOpenOption.READ);
}
}
if (null != is) {
try {
configurator.doConfigure(is);
} catch (JoranException e) { // NOPMD NOCHK StatusPrinter will handle this
} finally {
is.close();
}
}
} catch (IOException e) { // NOPMD NOCHK StatusPrinter will handle this
}
StatusPrinter.printInCaseOfErrorsOrWarnings(context);
// use sysout-over-slf4j to redirect out and err calls to logger
SysOutOverSLF4J.sendSystemOutAndErrToSLF4J();
// initialize out minlog bridge to the slf4j
MinlogToSLF4JLogger.init();
}
/**
* Main method of class.
*
* @param args
* The arguments.
*/
public static void main(String[] args) {
// Start Apache Procrun only if it's a Windows operating system.
if ((args.length == 1) && SystemUtils.IS_OS_WINDOWS) {
switch (args[0]) {
case "start":
start(args);
break;
case "stop":
stop(args);
break;
default:
startCMR();
}
} else {
startCMR();
}
}
/**
* Returns the spring bean factory.
*
* @return The spring bean factory.
*/
public static BeanFactory getBeanFactory() {
return beanFactory;
}
/**
* Getter method for property <code>startedAsService</code>.
*
* @return startedAsService.
*/
public static boolean isStartedAsService() {
return startedAsService;
}
}