/** * Handles the following tokens: * * <p>--L -L --l -l * * @param token the command line token to handle */ private void handleLongOptionWithoutEqual(String token) throws ParseException { List<String> matchingOpts = options.getMatchingOptions(token); if (matchingOpts.isEmpty()) { handleUnknownToken(currentToken); } else if (matchingOpts.size() > 1) { throw new AmbiguousOptionException(token, matchingOpts); } else { handleOption(options.getOption(matchingOpts.get(0))); } }
/** * If an {@link Option} exists for <code>token</code> then add the token to the processed list. * * <p>If an {@link Option} does not exist and <code>stopAtNonOption</code> is set then add the * remaining tokens to the processed tokens list directly. * * @param token The current option token * @param stopAtNonOption Specifies whether flattening should halt at the first non option. */ private void processOptionToken(String token, boolean stopAtNonOption) { if (stopAtNonOption && !options.hasOption(token)) { eatTheRest = true; } if (options.hasOption(token)) { currentOption = options.getOption(token); } else { currentOption = null; } tokens.add(token); }
/** * An implementation of {@link Parser}'s abstract {@link Parser#flatten(Options,String[],boolean) * flatten} method. * * <p>The following are the rules used by this flatten method. * * <ol> * <li>if <code>stopAtNonOption</code> is <b>true</b> then do not burst anymore of <code> * arguments</code> entries, just add each successive entry without further processing. * Otherwise, ignore <code>stopAtNonOption</code>. * <li>if the current <code>arguments</code> entry is "<b>--</b>" just add the entry to the list * of processed tokens * <li>if the current <code>arguments</code> entry is "<b>-</b>" just add the entry to the list * of processed tokens * <li>if the current <code>arguments</code> entry is two characters in length and the first * character is "<b>-</b>" then check if this is a valid {@link Option} id. If it is a valid * id, then add the entry to the list of processed tokens and set the current {@link Option} * member. If it is not a valid id and <code>stopAtNonOption</code> is true, then the * remaining entries are copied to the list of processed tokens. Otherwise, the current * entry is ignored. * <li>if the current <code>arguments</code> entry is more than two characters in length and the * first character is "<b>-</b>" then we need to burst the entry to determine its * constituents. For more information on the bursting algorithm see {@link * GroovyInternalPosixParser#burstToken(String, boolean) burstToken}. * <li>if the current <code>arguments</code> entry is not handled by any of the previous rules, * then the entry is added to the list of processed tokens. * </ol> * * @param options The command line {@link Options} * @param arguments The command line arguments to be parsed * @param stopAtNonOption Specifies whether to stop flattening when an non option is found. * @return The flattened <code>arguments</code> String array. */ protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) { init(); this.options = options; // an iterator for the command line tokens Iterator iter = Arrays.asList(arguments).iterator(); // process each command line token while (iter.hasNext()) { // get the next command line token String token = (String) iter.next(); // handle long option --foo or --foo=bar if (token.startsWith("--")) { int pos = token.indexOf('='); String opt = pos == -1 ? token : token.substring(0, pos); // --foo if (!options.hasOption(opt)) { processNonOptionToken(token, stopAtNonOption); } else { tokens.add(opt); if (pos != -1) { tokens.add(token.substring(pos + 1)); } else { currentOption = options.getOption(opt); } } } // single hyphen else if ("-".equals(token)) { tokens.add(token); } else if (token.startsWith("-")) { if (token.length() == 2 || options.hasOption(token)) { processOptionToken(token, stopAtNonOption); } // requires bursting else { burstToken(token, stopAtNonOption); } } else { processNonOptionToken(token, stopAtNonOption); } gobble(iter); } return (String[]) tokens.toArray(new String[tokens.size()]); }
/** * Breaks <code>token</code> into its constituent parts using the following algorithm. * * <ul> * <li>ignore the first character ("<b>-</b>") * <li>foreach remaining character check if an {@link Option} exists with that id. * <li>if an {@link Option} does exist then add that character prepended with "<b>-</b>" to the * list of processed tokens. * <li>if the {@link Option} can have an argument value and there are remaining characters in * the token then add the remaining characters as a token to the list of processed tokens. * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> <code>stopAtNonOption</code> * <b>IS</b> set then add the special token "<b>--</b>" followed by the remaining characters * and also the remaining tokens directly to the processed tokens list. * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> <code>stopAtNonOption</code> <b>IS * NOT</b> set then add that character prepended with "<b>-</b>". * </ul> * * @param token The current token to be <b>burst</b> at the first non-Option encountered. * @throws ParseException if there are any problems encountered while parsing the command line * token. */ protected void handleConcatenatedOptions(String token) throws ParseException { for (int i = 1; i < token.length(); i++) { String ch = String.valueOf(token.charAt(i)); if (options.hasOption(ch)) { handleOption(options.getOption(ch)); if (currentOption != null && token.length() != i + 1) { // add the trail as an argument of the option currentOption.addValueForProcessing(token.substring(i + 1)); break; } } else { handleUnknownToken(stopAtNonOption && i > 1 ? token.substring(i) : token); break; } } }
/** * Breaks <code>token</code> into its constituent parts using the following algorithm. * * <ul> * <li>ignore the first character ("<b>-</b>") * <li>foreach remaining character check if an {@link Option} exists with that id. * <li>if an {@link Option} does exist then add that character prepended with "<b>-</b>" to the * list of processed tokens. * <li>if the {@link Option} can have an argument value and there are remaining characters in * the token then add the remaining characters as a token to the list of processed tokens. * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> <code>stopAtNonOption</code> * <b>IS</b> set then add the special token "<b>--</b>" followed by the remaining characters * and also the remaining tokens directly to the processed tokens list. * <li>if an {@link Option} does <b>NOT</b> exist <b>AND</b> <code>stopAtNonOption</code> <b>IS * NOT</b> set then add that character prepended with "<b>-</b>". * </ul> * * @param token The current token to be <b>burst</b> * @param stopAtNonOption Specifies whether to stop processing at the first non-Option * encountered. */ protected void burstToken(String token, boolean stopAtNonOption) { for (int i = 1; i < token.length(); i++) { String ch = String.valueOf(token.charAt(i)); if (options.hasOption(ch)) { tokens.add("-" + ch); currentOption = options.getOption(ch); if (currentOption.hasArg() && (token.length() != (i + 1))) { tokens.add(token.substring(i + 1)); break; } } else if (stopAtNonOption) { processNonOptionToken(token.substring(i), true); break; } else { tokens.add(token); break; } } }
/** * Sets the values of Options using the values in <code>properties</code>. * * @param properties The value properties to be processed. */ private void handleProperties(Properties properties) throws ParseException { if (properties == null) { return; } for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements(); ) { String option = e.nextElement().toString(); Option opt = options.getOption(option); if (opt == null) { throw new UnrecognizedOptionException("Default option wasn't defined", option); } // if the option is part of a group, check if another option of the group has been selected OptionGroup group = options.getOptionGroup(opt); boolean selected = group != null && group.getSelected() != null; if (!cmd.hasOption(option) && !selected) { // get the value from the properties String value = properties.getProperty(option); if (opt.hasArg()) { if (opt.getValues() == null || opt.getValues().length == 0) { opt.addValueForProcessing(value); } } else if (!("yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value) || "1".equalsIgnoreCase(value))) { // if the value is not yes, true or 1 then don't add the option to the CommandLine continue; } handleOption(opt); currentOption = null; } } }
/** * Handles the following tokens: * * <p>--L=V -L=V --l=V -l=V * * @param token the command line token to handle */ private void handleLongOptionWithEqual(String token) throws ParseException { int pos = token.indexOf('='); String value = token.substring(pos + 1); String opt = token.substring(0, pos); List<String> matchingOpts = options.getMatchingOptions(opt); if (matchingOpts.isEmpty()) { handleUnknownToken(currentToken); } else if (matchingOpts.size() > 1) { throw new AmbiguousOptionException(opt, matchingOpts); } else { Option option = options.getOption(matchingOpts.get(0)); if (option.acceptsArg()) { handleOption(option); currentOption.addValueForProcessing(value); currentOption = null; } else { handleUnknownToken(currentToken); } } }
/** Check if the specified token is a Java-like property (-Dkey=value). */ private boolean isJavaProperty(String token) { String opt = token.substring(0, 1); Option option = options.getOption(opt); return option != null && (option.getArgs() >= 2 || option.getArgs() == Option.UNLIMITED_VALUES); }
/** * Handles the following tokens: * * <p>-S -SV -S V -S=V -S1S2 -S1S2 V -SV1=V2 * * <p>-L -LV -L V -L=V -l * * @param token the command line token to handle */ private void handleShortAndLongOption(String token) throws ParseException { String t = Util.stripLeadingHyphens(token); int pos = t.indexOf('='); if (t.length() == 1) { // -S if (options.hasShortOption(t)) { handleOption(options.getOption(t)); } else { handleUnknownToken(token); } } else if (pos == -1) { // no equal sign found (-xxx) if (options.hasShortOption(t)) { handleOption(options.getOption(t)); } else if (!options.getMatchingOptions(t).isEmpty()) { // -L or -l handleLongOptionWithoutEqual(token); } else { // look for a long prefix (-Xmx512m) String opt = getLongPrefix(t); if (opt != null && options.getOption(opt).acceptsArg()) { handleOption(options.getOption(opt)); currentOption.addValueForProcessing(t.substring(opt.length())); currentOption = null; } else if (isJavaProperty(t)) { // -SV1 (-Dflag) handleOption(options.getOption(t.substring(0, 1))); currentOption.addValueForProcessing(t.substring(1)); currentOption = null; } else { // -S1S2S3 or -S1S2V handleConcatenatedOptions(token); } } } else { // equal sign found (-xxx=yyy) String opt = t.substring(0, pos); String value = t.substring(pos + 1); if (opt.length() == 1) { // -S=V Option option = options.getOption(opt); if (option != null && option.acceptsArg()) { handleOption(option); currentOption.addValueForProcessing(value); currentOption = null; } else { handleUnknownToken(token); } } else if (isJavaProperty(opt)) { // -SV1=V2 (-Dkey=value) handleOption(options.getOption(opt.substring(0, 1))); currentOption.addValueForProcessing(opt.substring(1)); currentOption.addValueForProcessing(value); currentOption = null; } else { // -L=V or -l=V handleLongOptionWithEqual(token); } } }
public static void main(String[] args) throws Exception { boolean isInteractive = false; classUrl = MynaInstaller.class.getResource("MynaInstaller.class").toString(); isJar = (classUrl.indexOf("jar") == 0); if (!isJar) { System.err.println("Installer can only be run from inside a Myna distribution war file"); System.exit(1); } Thread.sleep(1000); Console console = System.console(); String response = null; CommandLineParser parser = new PosixParser(); // create the Options Options options = new Options(); options.addOption( "c", "context", true, "Webapp context. Must Start with \"/\" Default: " + webctx); options.addOption("h", "help", false, "Displays help."); options.addOption( "w", "webroot", true, "Webroot to use. Will be created if webroot/WEB-INF does not exist. Default: " + webroot); options.addOption( "l", "logfile", true, "Log file to use. Will be created if it does not exist. Default: ./<context>.log"); options.addOption( "s", "servername", true, "Name of this instance. Will also be the name of the init script. Defaults to either \"myna\" or the value of <context> if defined"); // options.addOption( "P", "purpose", true, "Purpose of the Server, such as DEV,PROD,TRAIN, etc. // Defaults to DEV" ); options.addOption("p", "port", true, "HTTP port. Set to 0 to disable HTTP. Default: " + port); options.addOption( "sp", "ssl-port", true, "SSL (HTTPS) port. Set to 0 to disable SSL, Default: 0"); options.addOption( "ks", "keystore", true, "keystore path. Default: <webroot>/WEB-INF/myna/myna_keystore"); options.addOption("ksp", "ks-pass", true, "keystore password. Default: " + ksPass); options.addOption("ksa", "ks-alias", true, "certificate alias. Default: " + ksAlias); modeOptions.add("upgrade"); modeOptions.add("install"); options.addOption( "m", "mode", true, "Mode: one of " + modeOptions.toString() + ". \n" + "\"upgrade\": Upgrades myna installation in webroot and exits. " + "\"install\": Unpacks to webroot, and installs startup files"); options.addOption( "u", "user", true, "User to own and run the Myna installation. Only applies to unix installs. Default: nobody"); HelpFormatter formatter = new HelpFormatter(); String cmdSyntax = "java -jar myna-X.war -m <mode> [options]"; try { CommandLine line = parser.parse(options, args); Option option; if (args.length == 0) { formatter.printHelp(cmdSyntax, options); response = console.readLine("\nContinue with Interactive Install? (y/N)"); if (response.toLowerCase().equals("y")) { isInteractive = true; } else System.exit(1); } // Help if (line.hasOption("help")) { formatter.printHelp(cmdSyntax, options); System.exit(1); } // mode if (line.hasOption("mode")) { mode = line.getOptionValue("mode"); if (!modeOptions.contains(mode)) { System.err.println( "Invalid Arguments. Reason: Mode must be in " + modeOptions.toString()); formatter.printHelp(cmdSyntax, options); System.exit(1); } } else if (isInteractive) { option = options.getOption("mode"); console.printf("\n" + option.getDescription()); do { response = console.readLine("\nEnter " + option.getLongOpt() + "(" + mode + "): "); if (!response.isEmpty()) mode = response; } while (!modeOptions.contains(mode)); } // webroot if (line.hasOption("webroot")) { webroot = line.getOptionValue("webroot"); } else if (isInteractive) { option = options.getOption("webroot"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + webroot + "): "); if (!response.isEmpty()) webroot = response; } // port if (line.hasOption("port")) { port = Integer.parseInt(line.getOptionValue("port")); } else if (isInteractive && mode.equals("install")) { option = options.getOption("port"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + port + "): "); if (!response.isEmpty()) port = Integer.parseInt(response); } // context if (line.hasOption("context")) { webctx = line.getOptionValue("context"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("context"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + webctx + "): "); if (!response.isEmpty()) webctx = response; } if (!webctx.startsWith("/")) { webctx = "/" + webctx; } // servername (depends on context) if (!webctx.equals("/")) { serverName = webctx.substring(1); } if (line.hasOption("servername")) { serverName = line.getOptionValue("servername"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("servername"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + serverName + "): "); if (!response.isEmpty()) serverName = response; } // user if (line.hasOption("user")) { user = line.getOptionValue("user"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("user"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + user + "): "); if (!response.isEmpty()) user = response; } // logfile logFile = "myna.log"; if (!webctx.equals("/")) { logFile = webctx.substring(1) + ".log"; } if (line.hasOption("logfile")) { logFile = line.getOptionValue("logfile"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("logfile"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "path(" + logFile + "): "); if (!response.isEmpty()) logFile = response; } // ssl-port if (line.hasOption("ssl-port")) { sslPort = Integer.parseInt(line.getOptionValue("ssl-port")); } else if (isInteractive && mode.equals("install")) { option = options.getOption("ssl-port"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + sslPort + "): "); if (!response.isEmpty()) sslPort = Integer.parseInt(response); } // ks-pass if (line.hasOption("ks-pass")) { ksPass = line.getOptionValue("ks-pass"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("ks-pass"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + ksPass + "): "); if (!response.isEmpty()) ksPass = response; } // ks-alias if (line.hasOption("ks-alias")) { ksAlias = line.getOptionValue("ks-alias"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("ks-alias"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + ksAlias + "): "); if (!response.isEmpty()) ksAlias = response; } // keystore String appBase = new File(webroot).getCanonicalPath(); if (keystore == null) { keystore = appBase + "/WEB-INF/myna/myna_keystore"; } if (line.hasOption("keystore")) { keystore = line.getOptionValue("keystore"); } else if (isInteractive && mode.equals("install")) { option = options.getOption("keystore"); console.printf("\n" + option.getDescription()); response = console.readLine("\nEnter " + option.getLongOpt() + "(" + keystore + "): "); if (!response.isEmpty()) keystore = response; } javaOpts = line.getArgList(); } catch (ParseException exp) { System.err.println("Invalid Arguments. Reason: " + exp.getMessage()); formatter.printHelp(cmdSyntax, options); System.exit(1); } if (isInteractive) { System.out.println("\nProceeed with the following settings?:\n"); System.out.println("mode = " + mode); System.out.println("webroot = " + webroot); if (mode.equals("install")) { System.out.println("port = " + port); System.out.println("context = " + webctx); System.out.println("servername = " + serverName); System.out.println("user = "******"logfile = " + logFile); System.out.println("ssl-port = " + sslPort); System.out.println("ks-pass = "******"ks-alias = " + ksAlias); System.out.println("keystore = " + keystore); } response = console.readLine("Continue? (Y/n)"); if (response.toLowerCase().equals("n")) System.exit(1); } File wrFile = new File(webroot); webroot = wrFile.toString(); if (mode.equals("install")) { adminPassword = console.readLine("\nCreate an Admin password for this installation: "); } // unpack myna if necessary if (!wrFile.exists() || mode.equals("upgrade") || mode.equals("install")) { upgrade(wrFile); } if (mode.equals("install")) { File propertiesFile = new File(wrFile.toURI().resolve("WEB-INF/classes/general.properties")); FileInputStream propertiesFileIS = new FileInputStream(propertiesFile); Properties generalProperties = new Properties(); generalProperties.load(propertiesFileIS); propertiesFileIS.close(); if (!adminPassword.isEmpty()) { org.jasypt.util.password.StrongPasswordEncryptor cryptTool = new org.jasypt.util.password.StrongPasswordEncryptor(); generalProperties.setProperty("admin_password", cryptTool.encryptPassword(adminPassword)); } generalProperties.setProperty("instance_id", serverName); generalProperties.store( new java.io.FileOutputStream(propertiesFile), "Myna General Properties"); String javaHome = System.getProperty("java.home"); webroot = new File(webroot).getCanonicalPath(); if (serverName.length() == 0) serverName = "myna"; if (java.lang.System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { if (!new File(logFile).isAbsolute()) { logFile = new File(wrFile.toURI().resolve("WEB-INF/" + logFile)).toString(); } File templateFile = new File( wrFile.toURI().resolve("WEB-INF/myna/install/windows/update_myna_service.cmd")); String initScript = FileUtils.readFileToString(templateFile) .replaceAll("\\{webctx\\}", webctx) .replaceAll("\\{server\\}", Matcher.quoteReplacement(serverName)) .replaceAll("\\{webroot\\}", Matcher.quoteReplacement(webroot)) .replaceAll("\\{logfile\\}", Matcher.quoteReplacement(logFile)) .replaceAll("\\{javahome\\}", Matcher.quoteReplacement(javaHome)) .replaceAll("\\{port\\}", new Integer(port).toString()) .replaceAll("\\{sslPort\\}", new Integer(sslPort).toString()) .replaceAll("\\{keystore\\}", Matcher.quoteReplacement(keystore)) .replaceAll("\\{ksPass\\}", Matcher.quoteReplacement(ksPass)) .replaceAll("\\{ksAlias\\}", Matcher.quoteReplacement(ksAlias)); File scriptFile = new File(wrFile.toURI().resolve("WEB-INF/myna/install/update_myna_service.cmd")); FileUtils.writeStringToFile(scriptFile, initScript); // Runtime.getRuntime().exec("cmd /c start " + scriptFile.toString()).waitFor(); System.out.println( "\nInstalled Service 'Myna App Server " + serverName + "' the following settings:\n"); System.out.println( "\nInit script '" + scriptFile + "' created with the following settings:\n"); System.out.println("memory=256MB"); System.out.println("serverName=" + serverName); System.out.println("javaHome=" + javaHome); System.out.println("context=" + webctx); System.out.println("port=" + port); System.out.println("myna_home=" + webroot); System.out.println("logfile=" + logFile); System.out.println("sslPort=" + sslPort); System.out.println("keyStore=" + keystore); System.out.println("ksPass="******"ksAlias=" + ksAlias); System.out.println( "\nEdit and and run the command file in " + scriptFile + " to update this service"); } else { String curUser = java.lang.System.getProperty("user.name"); if (!curUser.equals("root")) { System.out.println("Install mode must be run as root."); System.exit(1); } if (!new File(logFile).isAbsolute()) { logFile = new File(wrFile.toURI().resolve("WEB-INF/" + logFile)).toString(); } File templateFile = new File(wrFile.toURI().resolve("WEB-INF/myna/install/linux/init_script")); String initScript = FileUtils.readFileToString(templateFile) .replaceAll("\\{webctx\\}", webctx) .replaceAll("\\{server\\}", serverName) .replaceAll("\\{user\\}", user) .replaceAll("\\{webroot\\}", webroot) .replaceAll("\\{javahome\\}", javaHome) .replaceAll("\\{logfile\\}", logFile) .replaceAll("\\{port\\}", new Integer(port).toString()) .replaceAll("\\{sslPort\\}", new Integer(sslPort).toString()) .replaceAll("\\{keystore\\}", keystore) .replaceAll("\\{ksPass\\}", ksPass) .replaceAll("\\{ksAlias\\}", ksAlias); File scriptFile = new File(wrFile.toURI().resolve("WEB-INF/myna/install/" + serverName)); FileUtils.writeStringToFile(scriptFile, initScript); if (new File("/etc/init.d").exists()) { exec("chown -R " + user + " " + webroot); exec("chown root " + scriptFile.toString()); exec("chmod 700 " + scriptFile.toString()); exec("cp " + scriptFile.toString() + " /etc/init.d/"); System.out.println( "\nInit script '/etc/init.d/" + serverName + "' created with the following settings:\n"); } else { System.out.println( "\nInit script '" + scriptFile + "' created with the following settings:\n"); } System.out.println("user="******"memory=256MB"); System.out.println("server=" + serverName); System.out.println("context=" + webctx); System.out.println("port=" + port); System.out.println("myna_home=" + webroot); System.out.println("logfile=" + logFile); System.out.println("sslPort=" + sslPort); System.out.println("keyStore=" + keystore); System.out.println("ksPass="******"ksAlias=" + ksAlias); System.out.println("\nEdit this file to customize startup behavior"); } } }