SHL-100,101,102

This commit is contained in:
mpollack
2013-07-23 03:00:44 -04:00
parent 62ca88f36f
commit c37f0fdae8
19 changed files with 166 additions and 72 deletions

View File

@@ -18,4 +18,4 @@ mockitoVersion = 1.8.5
# --------------------
# Project wide version
# --------------------
version=1.0.1.BUILD-SNAPSHOT
version=1.1.0.BUILD-SNAPSHOT

View File

@@ -1,4 +1,4 @@
springShellVersion = 1.0.1.BUILD-SNAPSHOT
springShellVersion = 1.1.0.BUILD-SNAPSHOT
log4jVersion = 1.2.17
version = 1.0.0.RELEASE

View File

@@ -11,7 +11,7 @@
<url>http://maven.apache.org</url>
<properties>
<spring.shell.version>1.0.0.RELEASE</spring.shell.version>
<spring.shell.version>1.1.0.BUILD-SNAPSHOT</spring.shell.version>
<jar.mainclass>org.springframework.shell.Bootstrap</jar.mainclass>
<log4j.version>1.2.17</log4j.version>
</properties>

View File

@@ -0,0 +1,40 @@
/*
* 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.samples.helloworld;
import java.io.IOException;
import org.springframework.shell.Bootstrap;
/**
* Driver class to run the helloworld example.
*
* @author Mark Pollack
*
*/
public class Main {
/**
* Main class that delegates to Spring Shell's Bootstrap class in order to simplify debugging inside an IDE
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Bootstrap.main(args);
}
}

View File

@@ -54,7 +54,7 @@ public class MyBannerProvider extends DefaultBannerProvider
}
@Override
public String name() {
return "helloworld";
public String getProviderName() {
return "Hello World Banner";
}
}

View File

@@ -28,15 +28,15 @@ import org.springframework.stereotype.Component;
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class MyHistoryFileNameProvider extends DefaultHistoryFileNameProvider{
public class MyHistoryFileNameProvider extends DefaultHistoryFileNameProvider {
public String getHistoryFileName() {
return "my.log";
}
@Override
public String name() {
return "my history file name provider";
public String getProviderName() {
return "My history file name provider";
}
}

View File

@@ -35,8 +35,8 @@ public class MyPromptProvider extends DefaultPromptProvider {
@Override
public String name() {
return "my prompt provider";
public String getProviderName() {
return "My prompt provider";
}
}

View File

@@ -3,7 +3,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.springframework.shell.samples.helloworld.commands" />

View File

@@ -19,10 +19,13 @@ import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
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.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.shell.core.ExitShellRequest;
import org.springframework.shell.core.JLineShellComponent;
import org.springframework.shell.core.Shell;
@@ -38,10 +41,13 @@ import org.springframework.util.StopWatch;
*/
public class Bootstrap {
private final static String[] CONTEXT_PATH = { "classpath*:/META-INF/spring/spring-shell-plugin.xml" };
private static Bootstrap bootstrap;
private AnnotationConfigApplicationContext parentApplicationContext;
private static StopWatch sw = new StopWatch("Spring Shell");
private static CommandLine commandLine;
private GenericApplicationContext ctx;
public static void main(String[] args) throws IOException {
@@ -60,25 +66,34 @@ public class Bootstrap {
}
public Bootstrap(String[] args) throws IOException {
commandLine = SimpleShellCommandLineOptions.parseCommandLine(args);
parentApplicationContext = new AnnotationConfigApplicationContext();
configureParentApplicationContext(parentApplicationContext);
ConfigurableApplicationContext childPluginApplicationContext = createChildPluginApplicationContext(parentApplicationContext);
parentApplicationContext.refresh();
childPluginApplicationContext.refresh();
this(args, CONTEXT_PATH);
}
public AnnotationConfigApplicationContext getParentApplicationContext() {
return parentApplicationContext;
public Bootstrap(String[] args, String[] contextPath) {
try {
commandLine = SimpleShellCommandLineOptions.parseCommandLine(args);
} catch (IOException e) {
throw new ShellException(e.getMessage(), e);
}
ctx = new GenericApplicationContext();
ctx.registerShutdownHook();
configureApplicationContext(ctx);
//built-in commands and converters
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(ctx);
scanner.scan("org.springframework.shell.commands", "org.springframework.shell.converters", "org.springframework.shell.plugin.support");
//user contributed commands
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((BeanDefinitionRegistry) ctx);
reader.loadBeanDefinitions(contextPath);
ctx.refresh();
}
public ApplicationContext getApplicationContext() {
return ctx;
}
private void configureParentApplicationContext(AnnotationConfigApplicationContext annctx) {
// create parent/base childPluginApplicationContext
private void configureApplicationContext(GenericApplicationContext annctx) {
createAndRegisterBeanDefinition(annctx, org.springframework.shell.converters.StringConverter.class);
createAndRegisterBeanDefinition(annctx,
org.springframework.shell.converters.AvailableCommandsConverter.class);
@@ -99,35 +114,21 @@ public class Bootstrap {
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");
}
/**
* Init plugin ApplicationContext
*
* @param annctx parent ApplicationContext in core spring shell
* @return new ApplicationContext in the plugin with core spring shell's context as parent
*/
private ConfigurableApplicationContext createChildPluginApplicationContext(AnnotationConfigApplicationContext annctx) {
return new ClassPathXmlApplicationContext(
new String[] { "classpath*:/META-INF/spring/spring-shell-plugin.xml" }, false, annctx);
}
protected void createAndRegisterBeanDefinition(AnnotationConfigApplicationContext annctx, Class clazz) {
protected void createAndRegisterBeanDefinition(GenericApplicationContext annctx, Class clazz) {
createAndRegisterBeanDefinition(annctx, clazz, null);
}
protected void createAndRegisterBeanDefinition(AnnotationConfigApplicationContext annctx, Class clazz, String name) {
protected void createAndRegisterBeanDefinition(GenericApplicationContext annctx, Class clazz, String name) {
RootBeanDefinition rbd = new RootBeanDefinition();
rbd.setBeanClass(clazz);
DefaultListableBeanFactory bf = (DefaultListableBeanFactory)annctx.getBeanFactory();
if (name != null) {
annctx.registerBeanDefinition(name, rbd);
bf.registerBeanDefinition(name, rbd);
}
else {
annctx.registerBeanDefinition(clazz.getSimpleName(), rbd);
bf.registerBeanDefinition(clazz.getSimpleName(), rbd);
}
}
@@ -152,7 +153,7 @@ public class Bootstrap {
String[] commandsToExecuteAndThenQuit = commandLine.getShellCommandsToExecute();
// The shell is used
JLineShellComponent shell = parentApplicationContext.getBean("shell", JLineShellComponent.class);
JLineShellComponent shell = ctx.getBean("shell", JLineShellComponent.class);
ExitShellRequest exitShellRequest;
if (null != commandsToExecuteAndThenQuit) {
@@ -181,7 +182,7 @@ public class Bootstrap {
shell.waitForComplete();
}
parentApplicationContext.close();
ctx.close();
sw.stop();
if (shell.isDevelopmentMode()) {
System.out.println("Total execution time: " + sw.getLastTaskTimeMillis() + " ms");
@@ -190,6 +191,6 @@ public class Bootstrap {
}
JLineShellComponent getJLineShellComponent() {
return parentApplicationContext.getBean("shell", JLineShellComponent.class);
return ctx.getBean("shell", JLineShellComponent.class);
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2011-2013 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;
/**
* Shell exception.
*
* @author David Wintefeldt
*/
public class ShellException extends RuntimeException {
private static final long serialVersionUID = 1123895874463364743L;
public ShellException() {}
public ShellException(String message) {
super(message);
}
public ShellException(Throwable t) {
super(t);
}
public ShellException(String message, Throwable t) {
super(message, t);
}
}

View File

@@ -22,6 +22,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
@@ -36,8 +38,9 @@ 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;
import org.springframework.shell.plugin.NamedProvider;
import org.springframework.shell.plugin.PromptProvider;
import org.springframework.shell.support.logging.HandlerUtils;
/**
* Launcher for {@link JLineShell}.
@@ -187,7 +190,9 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A
* @return history file name
*/
protected String getHistoryFileName() {
String providerHistoryFileName = getHighestPriorityProvider(HistoryFileNameProvider.class).getHistoryFileName();
HistoryFileNameProvider historyFileNameProvider = getHighestPriorityProvider(HistoryFileNameProvider.class);
this.logger.log(Level.FINE, "Using HistoryFileName Provider Class " + historyFileNameProvider.getClass());
String providerHistoryFileName = historyFileNameProvider.getHistoryFileName();
if (providerHistoryFileName != null) {
return providerHistoryFileName;
} else {
@@ -202,7 +207,9 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A
* @return prompt text
*/
protected String getPromptText() {
String providerPromptText = getHighestPriorityProvider(PromptProvider.class).getPrompt();
PromptProvider promptProvider = getHighestPriorityProvider(PromptProvider.class);
this.logger.log(Level.FINE, "Using Prompt Provider Class " + promptProvider.getClass());
String providerPromptText = promptProvider.getPrompt();
if (providerPromptText != null) {
return providerPromptText;
} else {
@@ -221,15 +228,16 @@ public class JLineShellComponent extends JLineShell implements SmartLifecycle, A
private String[] getBannerText() {
String[] bannerText = new String[4];
BannerProvider provider = getHighestPriorityProvider(BannerProvider.class);
this.logger.log(Level.FINE, "Using BannerProvider class " + provider.getClass());
bannerText[0] = provider.getBanner();
bannerText[1] = provider.getWelcomeMessage();
bannerText[2] = provider.getVersion();
bannerText[3] = provider.name();
bannerText[3] = provider.getProviderName();
return bannerText;
}
private <T extends PluginProvider> T getHighestPriorityProvider(Class<T> t) {
private <T extends NamedProvider> T getHighestPriorityProvider(Class<T> t) {
Map<String, T> providers = BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, t);
List<T> sortedProviders = new ArrayList<T>(providers.values());
Collections.sort(sortedProviders, annotationOrderComparator);

View File

@@ -26,7 +26,7 @@ package org.springframework.shell.plugin;
* @since 1.0
*
*/
public interface BannerProvider extends PluginProvider {
public interface BannerProvider extends NamedProvider {
/**
* Returns the banner.

View File

@@ -25,7 +25,7 @@ package org.springframework.shell.plugin;
* @since 1.0
*
*/
public interface HistoryFileNameProvider extends PluginProvider {
public interface HistoryFileNameProvider extends NamedProvider {
/**
* get history file name

View File

@@ -16,16 +16,19 @@
package org.springframework.shell.plugin;
/**
* Generic plugin provider.
* Returns the name of the provider. Providers customize features of the shell such as the banner and command line prompt.
*
*
* @author Jarred Li
* @author Mark Pollack
* @see BannerProvider
* @see PromptProvider
* @see HistoryFileNameProvider
*/
public interface PluginProvider {
public interface NamedProvider {
/**
* Returns the name of the plugin.
*
* @return
* Return the name of the provider.
*/
String name();
String getProviderName();
}

View File

@@ -24,7 +24,7 @@ package org.springframework.shell.plugin;
* @author Jarred Li
*
*/
public interface PromptProvider extends PluginProvider {
public interface PromptProvider extends NamedProvider {
/**
* Returns the prompt text.

View File

@@ -48,10 +48,10 @@ public class DefaultBannerProvider implements BannerProvider {
}
public String getWelcomeMessage() {
return "Welcome to " + name() + ". For assistance press or type \"hint\" then hit ENTER.";
return "Welcome to " + getProviderName() + ". For assistance press or type \"hint\" then hit ENTER.";
}
public String name() {
public String getProviderName() {
return "Spring Shell";
}
}

View File

@@ -34,7 +34,7 @@ public class DefaultHistoryFileNameProvider implements HistoryFileNameProvider {
return "spring-shell.log";
}
public String name() {
public String getProviderName() {
return "default history provider";
}
}

View File

@@ -34,7 +34,7 @@ public class DefaultPromptProvider implements PromptProvider {
return "spring-shell>";
}
public String name() {
public String getProviderName() {
return "default prompt provider";
}
}

View File

@@ -22,7 +22,7 @@ import java.util.logging.Logger;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.shell.Bootstrap;
import org.springframework.shell.commands.test.OptionsInjectedDummyCommand;
import org.springframework.shell.support.logging.HandlerUtils;
@@ -33,7 +33,7 @@ public class CommandLineInjectedTest {
public void commandLineInjected() throws IOException {
try {
Bootstrap bootstrap = new Bootstrap(null);
AnnotationConfigApplicationContext ctx = bootstrap.getParentApplicationContext();
ApplicationContext ctx = bootstrap.getApplicationContext();
OptionsInjectedDummyCommand dummyCommand = ctx.getBean(OptionsInjectedDummyCommand.class);
Assert.assertNotNull("commandLine was not injected into a command", dummyCommand.getCommandLine());
} catch (RuntimeException t) {