/* * Copyright (c) NASK, NCSC * * This file is part of HoneySpider Network 2.1. * * This is a free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pl.nask.hsn2.framework.core; import java.io.FileNotFoundException; import java.io.IOException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.OptionBuilder; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.commons.daemon.Daemon; import org.apache.commons.daemon.DaemonContext; import org.apache.commons.daemon.DaemonController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.nask.hsn2.bus.api.BusException; import pl.nask.hsn2.bus.api.BusManager; import pl.nask.hsn2.bus.recovery.RecoveryMonitor; import pl.nask.hsn2.framework.bus.RbtBusConfiguration; import pl.nask.hsn2.framework.bus.RbtFrameworkBus; import pl.nask.hsn2.framework.configuration.Configuration; import pl.nask.hsn2.framework.configuration.ConfigurationException; import pl.nask.hsn2.framework.configuration.ConfigurationManager; import pl.nask.hsn2.framework.configuration.ConfigurationManagerImpl; import pl.nask.hsn2.framework.configuration.MappingException; import pl.nask.hsn2.framework.configuration.validation.ValidationException; import pl.nask.hsn2.framework.suppressor.SingleThreadTasksSuppressor; import pl.nask.hsn2.framework.workflow.repository.GitWorkflowRepository; import pl.nask.hsn2.framework.workflow.repository.WorkflowRepoException; import pl.nask.hsn2.utils.FileIdGenerator; import pl.nask.hsn2.workflow.engine.ActivitiWorkflowDefinitionManager; import pl.nask.hsn2.workflow.engine.ActivitiWorkflowEngine; /** * Main class for the HSN2 Framework. */ public class Main implements Daemon { private static Main instance; private Logger logger; private ConfigurationManager configManager; private static CommandLine commandLineParams; private RecoveryMonitor recoveryMonitor; private RbtFrameworkBus rbtBus; public static void main(final String[] args) throws Exception { Main worker = new Main(); worker.init(new DaemonContext() { @Override public DaemonController getController() { // TODO Auto-generated method stub return null; } @Override public String[] getArguments() { return args; } }); worker.start(); Thread.currentThread().join(); worker.stop(); worker.destroy(); } private void initWorkflowManager() throws ConfigurationException { Configuration configuration = configManager.getCurrentConfig(); GitWorkflowRepository repo; try { repo = new GitWorkflowRepository(configuration.getWorkflowRepositoryPath(), true); } catch (WorkflowRepoException e) { throw new ConfigurationException("Something is wrong with workflow repository at:'" + configuration.getWorkflowRepositoryPath()+"':"+e.getMessage(),e); } WorkflowManager.setWorkflowDefinitionManager(new ActivitiWorkflowDefinitionManager()); WorkflowManager.setKnownServiceNames(configuration.getAMQPServicesNames()); WorkflowManager.setWorkflowRepository(repo); // create jobs id generator to be used by the engine FileIdGenerator idGenerator = new FileIdGenerator(); idGenerator.setSequenceFile(configuration.getJobSequenceFile()); idGenerator.setForceCreate(false); if (!idGenerator.seqFileExists()) { throw new ConfigurationException( "Sequence file doesn't exist. Create it first: " + configuration.getJobSequenceFile() + " or change configuration key 'jobs.sequence.file' to point on correct file."); } // ONLY ONE SUPPRESSOR INSTANCE SHOULD BE USED HERE SingleThreadTasksSuppressor suppressor = new SingleThreadTasksSuppressor(configuration.getJobsSuppressorEnabled()); ActivitiWorkflowEngine engine = new ActivitiWorkflowEngine(idGenerator, suppressor, configuration.getJobsSuppressorBufferSize()); WorkflowManager.setWorkflowEngine(engine); // sets limits WorkflowManager.setMaximumRunningJobLimit(configuration.getJobsLimit()); WorkflowManager.getInstance(); } @SuppressWarnings("static-access") private static void parseCommandLineOptions(String[] args) { Options options = new Options(); options.addOption(OptionBuilder.withLongOpt("logFile").withArgName("file").hasArg().withDescription("use given file for log").create("lf")); options.addOption(OptionBuilder.withLongOpt("logLevel").withArgName("level").hasArg().withDescription("use given level for log").create("ll")); options.addOption(OptionBuilder.withLongOpt("configPath").withArgName("config").hasArg().withDescription("use given config path").create("cp")); options.addOption(OptionBuilder.withLongOpt("help").withDescription("this message").create("h")); options.addOption(OptionBuilder.withLongOpt("debug").withDescription("enable queues debug mode (turn off auto ack)").create("d")); try { commandLineParams = new PosixParser().parse(options, args); if (commandLineParams.hasOption("h")) { printHelpAndExit(options); } } catch (ParseException e) { System.err.println("Cannot parse command line options"); printHelpAndExit(options); } } private static void printHelpAndExit(Options options){ HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("java -jar ...", options ); System.exit(0); } protected void initConfiguration() throws ConfigurationException { try { ConfigurationManagerImpl mgr = new ConfigurationManagerImpl(); if (commandLineParams.hasOption("configPath")) { mgr.reloadConfig(commandLineParams.getOptionValue("configPath")); } else { mgr.reloadConfig(); } configManager = mgr; FrameworkContext.registerConfigurationManager(mgr); logger.info("Configuration loaded"); } catch (ConfigurationException e) { logger.error("Error loading configuration file", e); throw e; } catch (ValidationException e) { logger.error("Configuration file not valid", e); throw new ConfigurationException(e); } catch (MappingException e) { logger.error("Error loading configuration file", e); throw new ConfigurationException(e); } catch (FileNotFoundException e) { logger.error("Error initializing configuration ", e); throw new ConfigurationException(e); } catch (IOException e) { logger.error("Error initializing configuration ", e); throw new ConfigurationException(e); } } private void initBus() throws BusException { Configuration cfg = configManager.getCurrentConfig(); RbtBusConfiguration busConfig = new RbtBusConfiguration() .setAMQPServerAddress(cfg.getAMQPServerAddress()) .setAMQPFrameworkLowQueue(cfg.getAMQPFrameworkLowQueue()) .setAMQPFrameworkHighQueue(cfg.getAMQPFrameworkHighQueue()) .setServicesNames(cfg.getAMQPServicesNames()) .setOsLowQueueName(cfg.getAMQPObjectStoreQueueLow()) .setOsHiQueueName(cfg.getAMQPObjectStoreQueueHigh()) .setAmqpExchangeCommonName(cfg.getAMQPExchangeCommon()) .setAmqpExchangeMonitoringName(cfg.getAMQPExchangeMonitoring()) .setAmqpExchangeServicesName(cfg.getAMQPExchangeServices()) .setAmqpConsumersNumber(cfg.getAMQPConsumersNumber()); rbtBus = new RbtFrameworkBus(busConfig); rbtBus.initOutgoingConnectors(); BusManager.setBus(rbtBus); } private void startBus() throws BusException { rbtBus.start(); logger.info("AMQP will be started"); this.recoveryMonitor = new RecoveryMonitor(); recoveryMonitor.registerRecoverable(rbtBus); recoveryMonitor.start(); } private void initLogging() { if(commandLineParams.hasOption("logFile")){ LoggerManager.changeLog4jProperty("log4j.appender.PRIMARY.file", commandLineParams.getOptionValue("logFile")); } if(commandLineParams.hasOption("logLevel")){ LoggerManager.changeLogLevel(commandLineParams.getOptionValue("logLevel")); } logger = LoggerFactory.getLogger(Main.class); } @Override public void init(DaemonContext context) throws Exception { synchronized (this) { parseCommandLineOptions(context.getArguments()); if (instance != null) { // restart instance.stop(); } instance = this; try { // shutdown hook added Runtime.getRuntime().addShutdownHook(new Thread(){ @Override public void run() { try { instance.stop(); } catch (Exception e) { System.exit(0); } } }); initLogging(); initConfiguration(); initBus(); initWorkflowManager(); } catch (BusException e) { instance.logger.error("Framework cannot attach to the bus. Is Rabbit MQ working?"); instance.stop(); System.exit(1); } catch (ConfigurationException e) { instance.logger.error("Configuration Error:",e); instance.stop(); System.exit(1); } catch (Throwable tw) { instance.logger.error("Cought: ", tw); instance.stop(); System.exit(1); } } } @Override public void start() throws Exception { synchronized (this) { startBus(); logger.info("Framework started."); } } @Override public void stop() throws Exception { logger.debug("Stopping framework..."); try { // stopping recovery monitor if (recoveryMonitor != null) { recoveryMonitor.stop(); recoveryMonitor = null; } // stopping the bus if (rbtBus != null) { rbtBus.stop(); rbtBus = null; } } catch (Exception e) { logger.error("There are problems with shutdown the framework, ignoring.", e); } logger.info("Framework stopped."); } @Override public void destroy() { logger.info("Framework stopped."); } }