1047N/A/*
6302N/A * $Id$
6302N/A *
1047N/A * CDDL HEADER START
1047N/A *
1047N/A * The contents of this file are subject to the terms of the
1047N/A * Common Development and Distribution License, Version 1.0 only
1047N/A * (the "License"). You may not use this file except in compliance
1047N/A * with the License.
1047N/A *
1047N/A * You can obtain a copy of the license at
1047N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE
1047N/A * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
1047N/A * See the License for the specific language governing permissions
1047N/A * and limitations under the License.
1047N/A *
1047N/A * When distributing Covered Code, include this CDDL HEADER in each
1047N/A * file and include the License file at
1047N/A * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
1047N/A * add the following below this CDDL HEADER, with the fields enclosed
1047N/A * by brackets "[]" replaced with your own identifying information:
1047N/A * Portions Copyright [yyyy] [name of copyright owner]
1047N/A *
1047N/A * CDDL HEADER END
1047N/A *
1047N/A *
4576N/A * Copyright 2008-2009 Sun Microsystems, Inc.
6238N/A * Portions Copyright 2013 ForgeRock AS.
6302N/A * Portions Copyright 2013 Jens Elkner
1047N/A */
1047N/A
1047N/Apackage org.opends.quicksetup;
1047N/A
2086N/Aimport org.opends.messages.Message;
1907N/Aimport org.opends.server.util.args.ArgumentParser;
1342N/A
2086N/Aimport static org.opends.messages.QuickSetupMessages.*;
2549N/Aimport static org.opends.server.tools.ToolConstants.*;
2086N/Aimport static org.opends.server.util.DynamicConstants.PRINTABLE_VERSION_STRING;
2086N/A
1047N/Aimport org.opends.quicksetup.util.Utils;
1047N/A
1047N/Aimport java.io.PrintStream;
1237N/Aimport java.io.File;
1266N/Aimport java.util.logging.Level;
1237N/Aimport java.util.logging.Logger;
1047N/A
1047N/A/**
1047N/A * Responsible for providing initial evaluation of command line arguments
1047N/A * and determining whether to launch a CLI, GUI, or print a usage statement.
1047N/A */
1047N/Apublic abstract class Launcher {
1047N/A
1237N/A static private final Logger LOG = Logger.getLogger(Launcher.class.getName());
1237N/A
1047N/A /** Arguments with which this launcher was invoked. */
1047N/A protected String[] args;
1047N/A
1047N/A /**
1047N/A * Creates a Launcher.
1047N/A * @param args String[] of argument passes from the command line
1047N/A */
1047N/A public Launcher(String[] args) {
1047N/A if (args == null) {
1047N/A throw new IllegalArgumentException("args cannot be null");
1047N/A }
1047N/A this.args = args;
1907N/A
1047N/A }
1047N/A
1047N/A /**
1907N/A * Gets the arguments with which this launcher was invoked.
1907N/A * @return String[] args from the CLI invocation
1907N/A */
1907N/A public String[] getArguments() {
1907N/A return this.args;
1907N/A }
1907N/A
1907N/A /**
1907N/A * Gets an argument parser appropriate for this CLI launcher.
1907N/A *
1907N/A * @return ArgumentParser for parsing args
1907N/A */
1907N/A public abstract ArgumentParser getArgumentParser();
1907N/A
1907N/A /**
1047N/A * Indicates whether or not the launcher should print a usage
1047N/A * statement based on the content of the arguments passed into
1047N/A * the constructor.
1047N/A * @return boolean where true indicates usage should be printed
1047N/A */
1047N/A protected boolean shouldPrintUsage() {
1047N/A boolean printUsage = false;
1717N/A if ((args != null) && (args.length > 0)) {
1717N/A for (String arg : args) {
1777N/A if (arg.equals("-?") ||
1777N/A arg.equalsIgnoreCase("-H") ||
1717N/A arg.equalsIgnoreCase("--help")) {
1717N/A printUsage = true;
1047N/A }
1047N/A }
1047N/A }
1047N/A return printUsage;
1047N/A }
1047N/A
1047N/A /**
2324N/A * Indicates whether or not the launcher should print a usage
2324N/A * statement based on the content of the arguments passed into
2324N/A * the constructor.
2324N/A * @return boolean where true indicates usage should be printed
2324N/A */
2324N/A protected boolean isQuiet() {
2324N/A boolean printUsage = false;
2324N/A if ((args != null) && (args.length > 0)) {
2324N/A for (String arg : args) {
2324N/A if (arg.equals("-?") ||
2324N/A arg.equalsIgnoreCase("-Q") ||
2324N/A arg.equalsIgnoreCase("--quiet")) {
2324N/A printUsage = true;
2324N/A }
2324N/A }
2324N/A }
2324N/A return printUsage;
2324N/A }
2324N/A
2324N/A /**
1342N/A * Indicates whether or not the launcher should print a version
1342N/A * statement based on the content of the arguments passed into
1342N/A * the constructor.
1342N/A * @return boolean where true indicates version should be printed
1342N/A */
1342N/A protected boolean shouldPrintVersion() {
1342N/A boolean printVersion = false;
1342N/A if ((args != null) && (args.length > 0))
1342N/A {
1342N/A for (String arg : args)
1342N/A {
3011N/A if (arg.equalsIgnoreCase("--version"))
1342N/A {
1342N/A printVersion = true;
1342N/A }
1342N/A }
1342N/A }
1342N/A return printVersion;
1342N/A }
1343N/A
1342N/A /**
1047N/A * Indicates whether the launcher will launch a command line versus
1047N/A * a graphical application based on the contents of the arguments
1047N/A * passed into the constructor.
1343N/A *
1342N/A * @return boolean where true indicates that a CLI application
1342N/A * should be launched
1047N/A */
1047N/A protected boolean isCli() {
1047N/A boolean isCli = false;
1047N/A for (String arg : args) {
2549N/A if (arg.equalsIgnoreCase("--"+OPTION_LONG_CLI) ||
2549N/A arg.equalsIgnoreCase("-"+OPTION_SHORT_CLI)) {
1047N/A isCli = true;
1047N/A break;
1047N/A }
1047N/A }
1047N/A return isCli;
1047N/A }
1047N/A
1047N/A /**
1697N/A * Prints a usage message to the terminal.
1697N/A * @param i18nMsg localized user message that will be printed to the terminal.
1697N/A * @param toStdErr whether the message must be printed to the standard error
1697N/A * or the standard output.
1047N/A */
1697N/A protected void printUsage(String i18nMsg, boolean toStdErr) {
1697N/A if (toStdErr)
1697N/A {
1697N/A System.err.println(i18nMsg);
1697N/A }
1697N/A else
1697N/A {
1697N/A System.out.println(i18nMsg);
1697N/A }
1047N/A }
1047N/A
1047N/A /**
1047N/A * Launches the graphical uninstall. The graphical uninstall is launched in a
1047N/A * different thread that the main thread because if we have a problem with the
1047N/A * graphical system (for instance the DISPLAY environment variable is not
1047N/A * correctly set) the native libraries will call exit. However if we launch
1047N/A * this from another thread, the thread will just be killed.
1047N/A *
1047N/A * This code also assumes that if the call to SplashWindow.main worked (and
1047N/A * the splash screen was displayed) we will never get out of it (we will call
1047N/A * a System.exit() when we close the graphical uninstall dialog).
1047N/A *
1047N/A * @param args String[] the arguments used to call the SplashWindow main
1047N/A * method
1047N/A * @return 0 if everything worked fine, or 1 if we could not display properly
1047N/A * the SplashWindow.
1047N/A */
1047N/A protected int launchGui(final String[] args)
1047N/A {
3963N/A// Setup MacOSX native menu bar before AWT is loaded.
3963N/A Utils.setMacOSXMenuBar(getFrameTitle());
1047N/A final int[] returnValue =
1047N/A { -1 };
1047N/A Thread t = new Thread(new Runnable()
1047N/A {
1047N/A public void run()
1047N/A {
1147N/A try
1147N/A {
1147N/A SplashScreen.main(args);
1147N/A returnValue[0] = 0;
1147N/A }
1147N/A catch (Throwable t)
1147N/A {
1295N/A if (QuickSetupLog.isInitialized())
1295N/A {
1266N/A LOG.log(Level.WARNING, "Error launching GUI: "+t);
1295N/A StringBuilder buf = new StringBuilder();
1266N/A while (t != null)
1266N/A {
1266N/A StackTraceElement[] stack = t.getStackTrace();
1502N/A for (StackTraceElement aStack : stack) {
1502N/A buf.append(aStack.toString()).append("\n");
1266N/A }
1266N/A
1266N/A t = t.getCause();
1266N/A if (t != null)
1266N/A {
1295N/A buf.append("Root cause:\n");
1266N/A }
1266N/A }
1295N/A LOG.log(Level.WARNING, buf.toString());
1266N/A }
1147N/A }
1047N/A }
1047N/A });
1047N/A /*
1047N/A * This is done to avoid displaying the stack that might occur if there are
1047N/A * problems with the display environment.
1047N/A */
1047N/A PrintStream printStream = System.err;
2724N/A System.setErr(Utils.getEmptyPrintStream());
1047N/A t.start();
1047N/A try
1047N/A {
1047N/A t.join();
1047N/A }
1047N/A catch (InterruptedException ie)
1047N/A {
1047N/A /* An error occurred, so the return value will be -1. We got nothing to
1047N/A do with this exception. */
1047N/A }
1047N/A System.setErr(printStream);
1047N/A return returnValue[0];
1047N/A }
1047N/A
1047N/A /**
1047N/A * Gets the frame title of the GUI application that will be used
1047N/A * in some operating systems.
1047N/A * @return internationalized String representing the frame title
1047N/A */
2086N/A abstract protected Message getFrameTitle();
1047N/A
1047N/A /**
1047N/A * Launches the command line based uninstall.
1047N/A *
1047N/A * @param cliApp the CLI application to launch
1047N/A * @return 0 if everything worked fine, and an error code if something wrong
1047N/A * occurred.
1047N/A */
1935N/A protected int launchCli(CliApplication cliApp)
1935N/A {
2287N/A System.setProperty(Constants.CLI_JAVA_PROPERTY, "true");
1907N/A QuickSetupCli cli = new QuickSetupCli(cliApp, this);
2324N/A ReturnCode returnValue = cli.run();
2324N/A if (returnValue.equals(ReturnCode.USER_DATA_ERROR))
1935N/A {
1697N/A printUsage(true);
2324N/A System.exit(ReturnCode.USER_DATA_ERROR.getReturnCode());
1047N/A }
4576N/A else if (returnValue.equals(ReturnCode.CANCELED))
3397N/A {
4576N/A System.exit(ReturnCode.CANCELED.getReturnCode());
3397N/A }
3503N/A else if (returnValue.equals(ReturnCode.USER_INPUT_ERROR))
3503N/A {
3503N/A System.exit(ReturnCode.USER_INPUT_ERROR.getReturnCode());
3503N/A }
1935N/A return returnValue.getReturnCode();
1047N/A }
1047N/A
1047N/A /**
1697N/A * Prints the version statement to standard output terminal.
1047N/A */
2110N/A protected void printVersion()
1342N/A {
1349N/A System.out.print(PRINTABLE_VERSION_STRING);
1342N/A }
1342N/A
1342N/A /**
1342N/A * Prints a usage statement to terminal and exits with an error
1342N/A * code.
1697N/A * @param toStdErr whether the message must be printed to the standard error
1697N/A * or the standard output.
1342N/A */
1907N/A protected void printUsage(boolean toStdErr) {
1907N/A try
1907N/A {
1907N/A ArgumentParser argParser = getArgumentParser();
1907N/A if (argParser != null) {
1907N/A String msg = argParser.getUsage();
1907N/A printUsage(msg, toStdErr);
1907N/A }
1907N/A }
1907N/A catch (Throwable t)
1907N/A {
1907N/A System.out.println("ERROR: "+t);
1907N/A t.printStackTrace();
1907N/A }
1907N/A }
1047N/A
1047N/A /**
1047N/A * Creates a CLI application that will be run if the
1047N/A * launcher needs to launch a CLI application.
1047N/A * @return CliApplication that will be run
1047N/A */
1047N/A protected abstract CliApplication createCliApplication();
1047N/A
1047N/A /**
1047N/A * Called before the launcher launches the GUI. Here
1047N/A * subclasses can do any application specific things
1047N/A * like set system properties of print status messages
1047N/A * that need to be done before the GUI launches.
1047N/A */
1047N/A protected abstract void willLaunchGui();
1047N/A
1047N/A /**
1047N/A * Called if launching of the GUI failed. Here
1047N/A * subclasses can so application specific things
1047N/A * like print a message.
1295N/A * @param logFileName the log file containing more information about why
1295N/A * the launch failed.
1047N/A */
1295N/A protected abstract void guiLaunchFailed(String logFileName);
1047N/A
1047N/A /**
1697N/A * The main method which is called by the command lines.
1047N/A */
1759N/A public void launch() {
2324N/A if (shouldPrintVersion()) {
2324N/A ArgumentParser parser = getArgumentParser();
2324N/A if (parser == null || !parser.usageOrVersionDisplayed()) {
2324N/A printVersion();
2324N/A }
2324N/A System.exit(ReturnCode.PRINT_VERSION.getReturnCode());
1342N/A }
1342N/A else if (shouldPrintUsage()) {
2324N/A ArgumentParser parser = getArgumentParser();
2324N/A if (parser == null || !parser.usageOrVersionDisplayed()) {
2324N/A printUsage(false);
2324N/A }
2324N/A System.exit(ReturnCode.SUCCESSFUL.getReturnCode());
1047N/A } else if (isCli()) {
1516N/A CliApplication cliApp = createCliApplication();
1907N/A int exitCode = launchCli(cliApp);
1516N/A preExit(cliApp);
1759N/A System.exit(exitCode);
1047N/A } else {
1047N/A willLaunchGui();
1178N/A int exitCode = launchGui(args);
1047N/A if (exitCode != 0) {
1295N/A File logFile = QuickSetupLog.getLogFile();
1295N/A if (logFile != null)
1295N/A {
1295N/A guiLaunchFailed(logFile.toString());
1295N/A }
1295N/A else
1295N/A {
1295N/A guiLaunchFailed(null);
1295N/A }
2733N/A System.exit(exitCode);
1047N/A }
1047N/A }
1047N/A }
1047N/A
1516N/A private void preExit(CliApplication cliApp) {
1531N/A if (cliApp != null) {
1531N/A UserData ud = cliApp.getUserData();
2210N/A if (ud != null && !ud.isQuiet()) {
1516N/A
1531N/A // Add an extra space systematically
1531N/A System.out.println();
1516N/A
1531N/A File logFile = QuickSetupLog.getLogFile();
1531N/A if (logFile != null) {
2086N/A System.out.println(INFO_GENERAL_SEE_FOR_DETAILS.get(
2086N/A QuickSetupLog.getLogFile().getPath()));
1531N/A }
1516N/A }
1237N/A }
1237N/A }
1047N/A}