package fitnesseMain; import fitnesse.ConfigurationParameter; import fitnesse.ContextConfigurator; import fitnesse.FitNesse; import fitnesse.FitNesseContext; import fitnesse.Updater; import fitnesse.components.PluginsClassLoader; import fitnesse.reporting.ExitCodeListener; import fitnesse.socketservice.PlainServerSocketFactory; import fitnesse.socketservice.SslServerSocketFactory; import fitnesse.updates.WikiContentUpdater; import java.io.*; import java.net.BindException; import java.net.ServerSocket; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; import static fitnesse.ConfigurationParameter.*; public class FitNesseMain { private static final Logger LOG = Logger.getLogger(FitNesseMain.class.getName()); private final ExitCodeListener exitCodeListener = new ExitCodeListener(); public static void main(String[] args) throws Exception { Arguments arguments = null; try { arguments = new Arguments(args); } catch (IllegalArgumentException e) { Arguments.printUsage(); exit(1); } Integer exitCode = 0; try { exitCode = new FitNesseMain().launchFitNesse(arguments); } catch (Exception e){ LOG.log(Level.SEVERE, "Error while starting the FitNesse", e); exitCode = 1; } if (exitCode != null) { exit(exitCode); } } protected static void exit(int exitCode) { System.exit(exitCode); } public Integer launchFitNesse(Arguments arguments) throws Exception { ContextConfigurator contextConfigurator = ContextConfigurator.systemDefaults(); contextConfigurator = contextConfigurator.updatedWith(System.getProperties()); contextConfigurator = contextConfigurator.updatedWith(ConfigurationParameter.loadProperties(new File(arguments.getConfigFile(contextConfigurator)))); contextConfigurator = arguments.update(contextConfigurator); return launchFitNesse(contextConfigurator); } public Integer launchFitNesse(ContextConfigurator contextConfigurator) throws Exception { configureLogging("verbose".equalsIgnoreCase(contextConfigurator.get(LOG_LEVEL))); loadPlugins(contextConfigurator.get(ConfigurationParameter.ROOT_PATH)); if (contextConfigurator.get(COMMAND) != null) { contextConfigurator.withTestSystemListener(exitCodeListener); } FitNesseContext context = contextConfigurator.makeFitNesseContext(); if (!establishRequiredDirectories(context.getRootPagePath())) { LOG.severe("FitNesse cannot be started..."); LOG.severe("Unable to create FitNesse root directory in " + context.getRootPagePath()); LOG.severe("Ensure you have sufficient permissions to create this folder."); return 1; } logStartupInfo(context); if (update(context)) { LOG.info("**********************************************************"); LOG.info("Files have been updated to a new version."); LOG.info("Please read the release notes on "); LOG.info("http://localhost:" + context.port + "/FitNesse.ReleaseNotes"); LOG.info("to find out about the new features and fixes."); LOG.info("**********************************************************"); } if ("true".equalsIgnoreCase(contextConfigurator.get(INSTALL_ONLY))) { return null; } try { return launch(context); } catch (BindException e) { LOG.severe("FitNesse cannot be started..."); LOG.severe("Port " + context.port + " is already in use."); LOG.severe("Use the -p <port#> command line argument to use a different port."); return 1; } } private boolean establishRequiredDirectories(String rootPagePath) { return establishDirectory(new File(rootPagePath)) && establishDirectory(new File(rootPagePath, "files")); } private static boolean establishDirectory(File path) { return path.exists() || path.mkdir(); } private boolean update(FitNesseContext context) throws IOException { if (!"true".equalsIgnoreCase(context.getProperty(OMITTING_UPDATES.getKey()))) { Updater updater = new WikiContentUpdater(context); return updater.update(); } return false; } private void loadPlugins(String rootPath) throws Exception { new PluginsClassLoader(rootPath).addPluginsToClassLoader(); } private Integer launch(FitNesseContext context) throws Exception { if (!"true".equalsIgnoreCase(context.getProperty(INSTALL_ONLY.getKey()))) { String command = context.getProperty(COMMAND.getKey()); if (command != null) { String output = context.getProperty(OUTPUT.getKey()); executeSingleCommand(context.fitNesse, command, output); return exitCodeListener.getFailCount(); } else { LOG.info("Starting FitNesse on port: " + context.port); ServerSocket serverSocket = createServerSocket(context); context.fitNesse.start(serverSocket); } } return null; } private ServerSocket createServerSocket(FitNesseContext context) throws IOException { String protocol = context.getProperty(FitNesseContext.WIKI_PROTOCOL_PROPERTY); boolean useHTTPS = (protocol != null && protocol.equalsIgnoreCase("https")); String clientAuth = context.getProperty(FitNesseContext.SSL_CLIENT_AUTH_PROPERTY); final boolean sslClientAuth = (clientAuth != null && clientAuth.equalsIgnoreCase("required")); final String sslParameterClassName = context.getProperty(FitNesseContext.SSL_PARAMETER_CLASS_PROPERTY); return (useHTTPS ? new SslServerSocketFactory(sslClientAuth, sslParameterClassName) : new PlainServerSocketFactory()).createServerSocket(context.port); } private void executeSingleCommand(FitNesse fitNesse, String command, String outputFile) throws Exception { LOG.info("Executing command: " + command); OutputStream os; boolean outputRedirectedToFile = outputFile != null; if (outputRedirectedToFile) { LOG.info("Command Output redirected to: " + outputFile); os = new FileOutputStream(outputFile); } else { os = System.out; } fitNesse.executeSingleCommand(command, os); fitNesse.stop(); if (outputRedirectedToFile) { os.close(); } } private void logStartupInfo(FitNesseContext context) { // This message is on standard output for backward compatibility with Jenkins Fitnesse plugin. // (ConsoleHandler of JUL uses standard error output for all messages). System.out.println("Bootstrapping FitNesse, the fully integrated standalone wiki and acceptance testing framework."); LOG.info("root page: " + context.getRootPage()); LOG.info("logger: " + (context.logger == null ? "none" : context.logger.toString())); LOG.info("authenticator: " + context.authenticator); LOG.info("page factory: " + context.pageFactory); LOG.info("page theme: " + context.pageFactory.getTheme()); } public void configureLogging(boolean verbose) { if (loggingSystemPropertiesDefined()) { return; } InputStream in = FitNesseMain.class.getResourceAsStream((verbose ? "verbose-" : "") + "logging.properties"); try { LogManager.getLogManager().readConfiguration(in); } catch (Exception e) { LOG.log(Level.SEVERE, "Log configuration failed", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { LOG.log(Level.SEVERE, "Unable to close Log configuration file", e); } } } LOG.finest("Configured verbose logging"); } private boolean loggingSystemPropertiesDefined() { return System.getProperty("java.util.logging.config.class") != null || System.getProperty("java.util.logging.config.file") != null; } }