From 730e33d6ff317597200be26de46df04467bbed16 Mon Sep 17 00:00:00 2001 From: mpollack Date: Thu, 20 Dec 2012 05:41:45 +0800 Subject: [PATCH] SHL-66 - Plugins should have access to command line options --- .springBeans | 2 +- .../org/springframework/shell/Bootstrap.java | 47 ++++++-------- .../springframework/shell/CommandLine.java | 64 +++++++++++++++++++ .../shell/SimpleShellCommandLineOptions.java | 53 ++++++++------- .../shell/core/JLineShellComponent.java | 13 +++- .../test/OptionsInjectedDummyCommand.java | 24 +++++++ .../shell/core/CommandLineInjectedTest.java | 45 +++++++++++++ .../META-INF/spring/spring-shell-plugin.xml | 10 +++ 8 files changed, 203 insertions(+), 55 deletions(-) create mode 100644 src/main/java/org/springframework/shell/CommandLine.java create mode 100644 src/test/java/org/springframework/shell/commands/test/OptionsInjectedDummyCommand.java create mode 100644 src/test/java/org/springframework/shell/core/CommandLineInjectedTest.java create mode 100644 src/test/resources/META-INF/spring/spring-shell-plugin.xml diff --git a/.springBeans b/.springBeans index ea2a215b..7d843d92 100644 --- a/.springBeans +++ b/.springBeans @@ -7,7 +7,7 @@ - src/main/resources/META-INF/spring/test.xml + src/test/resources/META-INF/spring/spring-shell-plugin.xml diff --git a/src/main/java/org/springframework/shell/Bootstrap.java b/src/main/java/org/springframework/shell/Bootstrap.java index 44a487a0..69310cc9 100644 --- a/src/main/java/org/springframework/shell/Bootstrap.java +++ b/src/main/java/org/springframework/shell/Bootstrap.java @@ -16,17 +16,13 @@ package org.springframework.shell; import java.io.IOException; -import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; -import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.shell.core.CommandMarker; -import org.springframework.shell.core.Converter; import org.springframework.shell.core.ExitShellRequest; import org.springframework.shell.core.JLineShellComponent; import org.springframework.shell.core.Shell; @@ -36,8 +32,8 @@ import org.springframework.util.StopWatch; /** * Loads a {@link Shell} using Spring IoC container. * - * @author Ben Alex - * @since 1.0 + * @author Ben Alex (original Roo code) + * @author Mark Pollack * */ public class Bootstrap { @@ -46,21 +42,15 @@ public class Bootstrap { private JLineShellComponent shell; private AnnotationConfigApplicationContext parentApplicationContext; private static StopWatch sw = new StopWatch("Spring Shell"); - - //Initialize to empty option to facilitate testing of Bootstrap class - private static SimpleShellCommandLineOptions options = new SimpleShellCommandLineOptions(); + private static CommandLine commandLine; + public static void main(String[] args) throws IOException { sw.start(); - options = SimpleShellCommandLineOptions.parseCommandLine(args); - - for (Map.Entry entry : options.extraSystemProperties.entrySet()) { - System.setProperty(entry.getKey(), entry.getValue()); - } ExitShellRequest exitShellRequest; try { - bootstrap = new Bootstrap(null); - exitShellRequest = bootstrap.run(options.executeThenQuit); + bootstrap = new Bootstrap(args); + exitShellRequest = bootstrap.run(); } catch (RuntimeException t) { throw t; } finally { @@ -70,8 +60,10 @@ public class Bootstrap { System.exit(exitShellRequest.getExitCode()); } - public Bootstrap(String applicationContextLocation) throws IOException { - AnnotationConfigApplicationContext parentApplicationContext = new AnnotationConfigApplicationContext(); + public Bootstrap(String[] args) throws IOException { + commandLine = SimpleShellCommandLineOptions.parseCommandLine(args); + + parentApplicationContext = new AnnotationConfigApplicationContext(); configureParentApplicationContext(parentApplicationContext); ConfigurableApplicationContext childPluginApplicationContext = createChildPluginApplicationContext(parentApplicationContext); @@ -79,11 +71,10 @@ public class Bootstrap { parentApplicationContext.refresh(); childPluginApplicationContext.refresh(); - shell = childPluginApplicationContext.getBean("shell", JLineShellComponent.class); - shell.setHistorySize(options.historySize); - if (options.executeThenQuit != null) { - shell.setPrintBanner(false); - } + } + + public AnnotationConfigApplicationContext getParentApplicationContext() { + return parentApplicationContext; } private void configureParentApplicationContext(AnnotationConfigApplicationContext annctx) { @@ -107,7 +98,8 @@ public class Bootstrap { createAndRegisterBeanDefinition(annctx, org.springframework.shell.converters.StaticFieldConverterImpl.class); createAndRegisterBeanDefinition(annctx, org.springframework.shell.core.JLineShellComponent.class, "shell"); createAndRegisterBeanDefinition(annctx, org.springframework.shell.converters.SimpleFileConverter.class); - + + annctx.getBeanFactory().registerSingleton("commandLine", commandLine); annctx.scan("org.springframework.shell.commands"); annctx.scan("org.springframework.shell.converters"); annctx.scan("org.springframework.shell.plugin.support"); @@ -157,15 +149,16 @@ public class Bootstrap { } - protected ExitShellRequest run(String[] executeThenQuit) { + protected ExitShellRequest run() { + String[] commandsToExecuteAndThenQuit = commandLine.getShellCommandsToExecute(); ExitShellRequest exitShellRequest; - if (null != executeThenQuit) { + if (null != commandsToExecuteAndThenQuit) { boolean successful = false; exitShellRequest = ExitShellRequest.FATAL_EXIT; - for (String cmd : executeThenQuit) { + for (String cmd : commandsToExecuteAndThenQuit) { successful = shell.executeCommand(cmd); if (!successful) break; diff --git a/src/main/java/org/springframework/shell/CommandLine.java b/src/main/java/org/springframework/shell/CommandLine.java new file mode 100644 index 00000000..3bca778b --- /dev/null +++ b/src/main/java/org/springframework/shell/CommandLine.java @@ -0,0 +1,64 @@ +/* + * Copyright 2011-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell; + + +/** + * Encapsulates the list of argument passed to the shell. + * + * @author Mark Pollack + */ +public class CommandLine { + + private String[] args; + private int historySize; + private String[] shellCommandsToExecute; + + /** + * Construct a new CommandLine + * @param args an array of strings from main(String[] args) + * @param historySize the size of this history buffer + * @param shellCommandsToExecute semi-colon delimited list of commands for the shell to execute + */ + public CommandLine(String[] args, int historySize, String[] shellCommandsToExecute) { + this.args = args; + this.historySize = historySize; + this.shellCommandsToExecute = shellCommandsToExecute; + } + + /** + * Return the command line arguments + * @return the command line arguments + */ + public String[] getArgs() { + return args; + } + + /** + * @return the historySize + */ + public int getHistorySize() { + return historySize; + } + + /** + * @return the shellCommandsToExecute + */ + public String[] getShellCommandsToExecute() { + return shellCommandsToExecute; + } + +} diff --git a/src/main/java/org/springframework/shell/SimpleShellCommandLineOptions.java b/src/main/java/org/springframework/shell/SimpleShellCommandLineOptions.java index f89f57de..5edff271 100644 --- a/src/main/java/org/springframework/shell/SimpleShellCommandLineOptions.java +++ b/src/main/java/org/springframework/shell/SimpleShellCommandLineOptions.java @@ -32,14 +32,18 @@ import org.springframework.shell.support.logging.HandlerUtils; * @author vnagaraja */ public class SimpleShellCommandLineOptions { - - private static final Logger LOGGER = HandlerUtils.getLogger(SimpleShellCommandLineOptions.class); - private static final int DEFAULT_HISTORY_SIZE = 3000; + + private static final Logger LOGGER = HandlerUtils.getLogger(SimpleShellCommandLineOptions.class); + public static final int DEFAULT_HISTORY_SIZE = 3000; String[] executeThenQuit = null; Map extraSystemProperties = new HashMap(); int historySize = DEFAULT_HISTORY_SIZE; - public static SimpleShellCommandLineOptions parseCommandLine(String[] args) throws IOException { + public static CommandLine parseCommandLine(String[] args) + throws IOException { + if (args == null) { + args = new String[] {}; + } SimpleShellCommandLineOptions options = new SimpleShellCommandLineOptions(); List commands = new ArrayList(); int i = 0; @@ -48,41 +52,37 @@ public class SimpleShellCommandLineOptions { if (arg.equals("--profiles")) { try { String profiles = args[i++]; - options.extraSystemProperties.put("spring.profiles.active", profiles); + options.extraSystemProperties.put("spring.profiles.active", profiles); } catch (ArrayIndexOutOfBoundsException e) { LOGGER.warning("No value specified for --profiles option"); } - } - else if (arg.equals("--cmdfile")) { + } else if (arg.equals("--cmdfile")) { try { File f = new File(args[i++]); - commands.addAll(FileUtils.readLines(f)); + commands.addAll(FileUtils.readLines(f)); } catch (IOException e) { - LOGGER.warning("Could not read lines from command file: " + e.getMessage()); + LOGGER.warning("Could not read lines from command file: " + e.getMessage()); } catch (ArrayIndexOutOfBoundsException e) { LOGGER.warning("No value specified for --cmdfile option"); } - } - else if (arg.equals("--histsize")) { - try { - String histSizeArg = args[i++]; + } else if (arg.equals("--histsize")) { + try { + String histSizeArg = args[i++]; int histSize = Integer.parseInt(histSizeArg); if (histSize <= 0) { LOGGER.warning("histsize option must be > 0, using default value of " + DEFAULT_HISTORY_SIZE); } else { - options.historySize = histSize; + options.historySize = histSize; } } catch (NumberFormatException e) { - LOGGER.warning("Unable to parse histsize value to an integer "); + LOGGER.warning("Unable to parse histsize value to an integer "); } catch (ArrayIndexOutOfBoundsException ae) { LOGGER.warning("No value specified for --histsize option"); } - } - else if (arg.equals("--help")) { + } else if (arg.equals("--help")) { printUsage(); System.exit(0); - } - else { + } else { i--; break; } @@ -99,18 +99,23 @@ public class SimpleShellCommandLineOptions { if (sb.length() > 0) { String[] cmdLineCommands = sb.toString().split(";"); for (String s : cmdLineCommands) { - //add any command line commands after the commands loaded from the file + // add any command line commands after the commands loaded from the file commands.add(s.trim()); } } - if (commands.size() > 0) + if (commands.size() > 0) { options.executeThenQuit = commands.toArray(new String[commands.size()]); + } - return options; + for (Map.Entry entry : options.extraSystemProperties.entrySet()) { + System.setProperty(entry.getKey(), entry.getValue()); + } + + return new CommandLine(args, options.historySize, options.executeThenQuit); } - - private static void printUsage(){ + + private static void printUsage() { System.out.println("Usage: --help --histsize [size] --cmdfile [file name] --profiles [comma-separated list of profile names]"); } } diff --git a/src/main/java/org/springframework/shell/core/JLineShellComponent.java b/src/main/java/org/springframework/shell/core/JLineShellComponent.java index f918ceca..c06821ca 100644 --- a/src/main/java/org/springframework/shell/core/JLineShellComponent.java +++ b/src/main/java/org/springframework/shell/core/JLineShellComponent.java @@ -33,6 +33,7 @@ import org.springframework.context.Lifecycle; import org.springframework.context.SmartLifecycle; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.io.Resource; +import org.springframework.shell.CommandLine; import org.springframework.shell.plugin.BannerProvider; import org.springframework.shell.plugin.HistoryFileNameProvider; import org.springframework.shell.plugin.PluginProvider; @@ -46,6 +47,9 @@ import org.springframework.shell.plugin.PromptProvider; */ public class JLineShellComponent extends JLineShell implements SmartLifecycle, ApplicationContextAware, InitializingBean { + @Autowired + private CommandLine commandLine; + private volatile boolean running = false; private Thread shellThread; @@ -61,8 +65,6 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A private String version; private String welcomeMessage; - - // Fields private ExecutionStrategy executionStrategy = new SimpleExecutionStrategy(); private SimpleParser parser = new SimpleParser(); @@ -114,6 +116,11 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A for (Converter converter : converters.values()) { getSimpleParser().add(converter); } + + setHistorySize(commandLine.getHistorySize()); + if (commandLine.getShellCommandsToExecute() != null) { + setPrintBanner(false); + } } /** @@ -231,7 +238,7 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A } public void printBannerAndWelcome() { - if (printBanner) { + if (printBanner) { logger.info(this.banner); logger.info(getWelcomeMessage()); } diff --git a/src/test/java/org/springframework/shell/commands/test/OptionsInjectedDummyCommand.java b/src/test/java/org/springframework/shell/commands/test/OptionsInjectedDummyCommand.java new file mode 100644 index 00000000..828b03eb --- /dev/null +++ b/src/test/java/org/springframework/shell/commands/test/OptionsInjectedDummyCommand.java @@ -0,0 +1,24 @@ +package org.springframework.shell.commands.test; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.shell.CommandLine; +import org.springframework.shell.core.CommandMarker; +import org.springframework.shell.core.annotation.CliCommand; +import org.springframework.stereotype.Component; + +@Component +public class OptionsInjectedDummyCommand implements CommandMarker { + + @Autowired + private CommandLine commandLine; + + @CliCommand("do nothing") + public String simple() { + return "foo"; + } + + public CommandLine getCommandLine() { + return commandLine; + } + +} diff --git a/src/test/java/org/springframework/shell/core/CommandLineInjectedTest.java b/src/test/java/org/springframework/shell/core/CommandLineInjectedTest.java new file mode 100644 index 00000000..c8663a84 --- /dev/null +++ b/src/test/java/org/springframework/shell/core/CommandLineInjectedTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.shell.core; + + +import java.io.IOException; +import java.util.logging.Logger; + +import junit.framework.Assert; + +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.shell.Bootstrap; +import org.springframework.shell.commands.test.OptionsInjectedDummyCommand; +import org.springframework.shell.support.logging.HandlerUtils; + +public class CommandLineInjectedTest { + + @Test + public void commandLineInjected() throws IOException { + try { + Bootstrap bootstrap = new Bootstrap(null); + AnnotationConfigApplicationContext ctx = bootstrap.getParentApplicationContext(); + OptionsInjectedDummyCommand dummyCommand = ctx.getBean(OptionsInjectedDummyCommand.class); + Assert.assertNotNull("commandLine was not injected into a command", dummyCommand.getCommandLine()); + } catch (RuntimeException t) { + throw t; + } finally { + HandlerUtils.flushAllHandlers(Logger.getLogger("")); + } + } +} diff --git a/src/test/resources/META-INF/spring/spring-shell-plugin.xml b/src/test/resources/META-INF/spring/spring-shell-plugin.xml new file mode 100644 index 00000000..49d5e66e --- /dev/null +++ b/src/test/resources/META-INF/spring/spring-shell-plugin.xml @@ -0,0 +1,10 @@ + + + + + +