// Path: falchion-container/src/main/java/net/unit8/falchion/evaluator/EvaluatorSupplier.java
// public enum EvaluatorSupplier {
//     MIN_GC_TIME(MinGcTime::new),
//     MIN_FULL_GC_COUNT(MinFullGcCount::new);
// 
//     EvaluatorSupplier(Supplier<Evaluator> supplier) {
//         this.supplier = supplier;
//     }
// 
//     Supplier<Evaluator> supplier;
// 
//     public Evaluator createEvaluator() {
//         return supplier.get();
//     }
// }
// 
// Path: falchion-container/src/main/java/net/unit8/falchion/monitor/MonitorSupplier.java
// public enum MonitorSupplier {
//     GCUTIL_JSTAT(JstatMonitor::new),
//     METRICS_JMX(MetricsJmxMonitor::new);
// 
//     private Supplier<JvmMonitor> monitorSupplier;
// 
//     MonitorSupplier(Supplier<JvmMonitor> monitorSupplier) {
//         this.monitorSupplier = monitorSupplier;
//     }
// 
//     public JvmMonitor createMonitor() {
//         return monitorSupplier.get();
//     }
// }


import net.unit8.falchion.evaluator.EvaluatorSupplier;
import net.unit8.falchion.monitor.MonitorSupplier;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.Messages;
import org.kohsuke.args4j.spi.StringArrayOptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Signal;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
package net.unit8.falchion;



/**
 * Bootstraps JVM container.
 *
 * @author kawasima
 */
public class Bootstrap {
    private static final Logger LOG = LoggerFactory.getLogger(Bootstrap.class);
    private static final Signal HUP  = new Signal("HUP");
    private static final Signal TERM = new Signal("TERM");

    @Option(name = "-cp", usage = "Class search path of directories and zip/jar files",
            metaVar = "CLASSPATH")
    private String classpath;

    @Option(name = "-m", usage = "name of JVM process monitor", handler = StringArrayOptionHandler.class)
    private String[] monitors = {};

    @Option(name = "-p", usage = "size of JVM processes", metaVar = "SIZE")
    private int poolSize = 1;

    @Option(name = "--admin-port", usage = "a port number of the api server", metaVar = "PORT")
    private int adminPort = 44010;

    @Option(name = "--auto-tuning", usage = "tuning JVM parameter automatically")
    private boolean autoTuning = false;

    @Option(name = "--evaluator", usage ="JVM parameter evaluator")
    private String evaluator;

    @Option(name = "--lifetime", usage = "lifetime of a jvm process",
            metaVar = "SEC")
    private long lifetime = 0;

    @Option(name = "-basedir", usage = "base directory of zip/jar files")
    private String basedir;

    @Option(name = "-v", usage = "application version")
    private String aplVersion;

    @Option(name = "--java-opts", usage = "options for worker processes",
            metaVar = "JAVA_OPTS")
    private String javaOpts;

    /** @noinspection MismatchedQueryAndUpdateOfCollection*/
    @Argument
    private List<String> arguments = new ArrayList<>();

    public void doMain(String... args) {
        CmdLineParser parser = new CmdLineParser(this);
        try {
            parser.parseArgument(args);
            if (arguments.isEmpty()) {
                throw new CmdLineException(parser, Messages.DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER);
            }
        } catch (CmdLineException ex) {
            ex.printStackTrace();
            parser.printUsage(System.err);
            return;
        }

        LOG.info("monitors={}", Arrays.asList(monitors));
        Set<MonitorSupplier> monitorSuppliers = Arrays.stream(monitors)
                .map(MonitorSupplier::valueOf)
                .collect(Collectors.toSet());

        Container container = new Container(poolSize);
        container.setMonitorSuppliers(monitorSuppliers);
        container.setAutoTuning(autoTuning);
        container.setBasedir(basedir);
        if (evaluator != null) {
// Path: falchion-container/src/main/java/net/unit8/falchion/evaluator/EvaluatorSupplier.java
// public enum EvaluatorSupplier {
//     MIN_GC_TIME(MinGcTime::new),
//     MIN_FULL_GC_COUNT(MinFullGcCount::new);
// 
//     EvaluatorSupplier(Supplier<Evaluator> supplier) {
//         this.supplier = supplier;
//     }
// 
//     Supplier<Evaluator> supplier;
// 
//     public Evaluator createEvaluator() {
//         return supplier.get();
//     }
// }
// 
// Path: falchion-container/src/main/java/net/unit8/falchion/monitor/MonitorSupplier.java
// public enum MonitorSupplier {
//     GCUTIL_JSTAT(JstatMonitor::new),
//     METRICS_JMX(MetricsJmxMonitor::new);
// 
//     private Supplier<JvmMonitor> monitorSupplier;
// 
//     MonitorSupplier(Supplier<JvmMonitor> monitorSupplier) {
//         this.monitorSupplier = monitorSupplier;
//     }
// 
//     public JvmMonitor createMonitor() {
//         return monitorSupplier.get();
//     }
// }


// Path: falchion-container/src/main/java/net/unit8/falchion/Bootstrap.java
import net.unit8.falchion.evaluator.EvaluatorSupplier;
import net.unit8.falchion.monitor.MonitorSupplier;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.spi.Messages;
import org.kohsuke.args4j.spi.StringArrayOptionHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Signal;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

package net.unit8.falchion;



/**
 * Bootstraps JVM container.
 *
 * @author kawasima
 */
public class Bootstrap {
    private static final Logger LOG = LoggerFactory.getLogger(Bootstrap.class);
    private static final Signal HUP  = new Signal("HUP");
    private static final Signal TERM = new Signal("TERM");

    @Option(name = "-cp", usage = "Class search path of directories and zip/jar files",
            metaVar = "CLASSPATH")
    private String classpath;

    @Option(name = "-m", usage = "name of JVM process monitor", handler = StringArrayOptionHandler.class)
    private String[] monitors = {};

    @Option(name = "-p", usage = "size of JVM processes", metaVar = "SIZE")
    private int poolSize = 1;

    @Option(name = "--admin-port", usage = "a port number of the api server", metaVar = "PORT")
    private int adminPort = 44010;

    @Option(name = "--auto-tuning", usage = "tuning JVM parameter automatically")
    private boolean autoTuning = false;

    @Option(name = "--evaluator", usage ="JVM parameter evaluator")
    private String evaluator;

    @Option(name = "--lifetime", usage = "lifetime of a jvm process",
            metaVar = "SEC")
    private long lifetime = 0;

    @Option(name = "-basedir", usage = "base directory of zip/jar files")
    private String basedir;

    @Option(name = "-v", usage = "application version")
    private String aplVersion;

    @Option(name = "--java-opts", usage = "options for worker processes",
            metaVar = "JAVA_OPTS")
    private String javaOpts;

    /** @noinspection MismatchedQueryAndUpdateOfCollection*/
    @Argument
    private List<String> arguments = new ArrayList<>();

    public void doMain(String... args) {
        CmdLineParser parser = new CmdLineParser(this);
        try {
            parser.parseArgument(args);
            if (arguments.isEmpty()) {
                throw new CmdLineException(parser, Messages.DEFAULT_META_EXPLICIT_BOOLEAN_OPTION_HANDLER);
            }
        } catch (CmdLineException ex) {
            ex.printStackTrace();
            parser.printUsage(System.err);
            return;
        }

        LOG.info("monitors={}", Arrays.asList(monitors));
        Set<MonitorSupplier> monitorSuppliers = Arrays.stream(monitors)
                .map(MonitorSupplier::valueOf)
                .collect(Collectors.toSet());

        Container container = new Container(poolSize);
        container.setMonitorSuppliers(monitorSuppliers);
        container.setAutoTuning(autoTuning);
        container.setBasedir(basedir);
        if (evaluator != null) {
            container.setEvaluator(EvaluatorSupplier.valueOf(evaluator).createEvaluator());