SHL-86 - Change bootstrapping procedure so JLineShellComponent can resolve its own dependencies.

This commit is contained in:
mpollack
2012-12-19 07:50:57 +08:00
parent 9ab78ddbbc
commit ecf06a70ee
5 changed files with 107 additions and 30 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ target/
/log.roo
/bin/
/*.log

View File

@@ -44,9 +44,11 @@ public class Bootstrap {
private static Bootstrap bootstrap;
private JLineShellComponent shell;
private ConfigurableApplicationContext ctx;
private AnnotationConfigApplicationContext parentApplicationContext;
private static StopWatch sw = new StopWatch("Spring Shell");
private static SimpleShellCommandLineOptions options;
//Initialize to empty option to facilitate testing of Bootstrap class
private static SimpleShellCommandLineOptions options = new SimpleShellCommandLineOptions();
public static void main(String[] args) throws IOException {
sw.start();
@@ -69,30 +71,24 @@ public class Bootstrap {
}
public Bootstrap(String applicationContextLocation) throws IOException {
//setupLogging();
createApplicationContext();
shell = ctx.getBean("shell", JLineShellComponent.class);
shell.setApplicationContext(ctx);
AnnotationConfigApplicationContext parentApplicationContext = new AnnotationConfigApplicationContext();
configureParentApplicationContext(parentApplicationContext);
ConfigurableApplicationContext childPluginApplicationContext = createChildPluginApplicationContext(parentApplicationContext);
parentApplicationContext.refresh();
childPluginApplicationContext.refresh();
shell = childPluginApplicationContext.getBean("shell", JLineShellComponent.class);
shell.setHistorySize(options.historySize);
if (options.executeThenQuit != null) {
shell.setPrintBanner(false);
}
Map<String, CommandMarker> commands = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, CommandMarker.class);
for (CommandMarker command : commands.values()) {
shell.getSimpleParser().add(command);
}
Map<String, Converter> converters = BeanFactoryUtils.beansOfTypeIncludingAncestors(ctx, Converter.class);
for (Converter converter : converters.values()) {
shell.getSimpleParser().add(converter);
}
}
private void createApplicationContext() {
// create parent/base ctx
AnnotationConfigApplicationContext annctx = new AnnotationConfigApplicationContext();
private void configureParentApplicationContext(AnnotationConfigApplicationContext annctx) {
// create parent/base childPluginApplicationContext
createAndRegisterBeanDefinition(annctx, org.springframework.shell.converters.StringConverter.class);
createAndRegisterBeanDefinition(annctx,
org.springframework.shell.converters.AvailableCommandsConverter.class);
@@ -115,10 +111,7 @@ public class Bootstrap {
annctx.scan("org.springframework.shell.commands");
annctx.scan("org.springframework.shell.converters");
annctx.scan("org.springframework.shell.plugin.support");
annctx.refresh();
ctx = initPluginApplicationContext(annctx);
ctx.refresh();
}
/**
@@ -127,9 +120,9 @@ public class Bootstrap {
* @param annctx parent ApplicationContext in core spring shell
* @return new ApplicationContext in the plugin with core spring shell's context as parent
*/
private ConfigurableApplicationContext initPluginApplicationContext(AnnotationConfigApplicationContext annctx) {
private ConfigurableApplicationContext createChildPluginApplicationContext(AnnotationConfigApplicationContext annctx) {
return new ClassPathXmlApplicationContext(
new String[] { "classpath*:/META-INF/spring/spring-shell-plugin.xml" }, true, annctx);
new String[] { "classpath*:/META-INF/spring/spring-shell-plugin.xml" }, false, annctx);
}
protected void createAndRegisterBeanDefinition(AnnotationConfigApplicationContext annctx, Class clazz) {
@@ -194,11 +187,15 @@ public class Bootstrap {
shell.waitForComplete();
}
ctx.close();
parentApplicationContext.close();
sw.stop();
if (shell.isDevelopmentMode()) {
System.out.println("Total execution time: " + sw.getLastTaskTimeMillis() + " ms");
}
return exitShellRequest;
}
JLineShellComponent getJLineShellComponent() {
return shell;
}
}

View File

@@ -25,8 +25,12 @@ import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
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.plugin.BannerProvider;
@@ -40,7 +44,7 @@ import org.springframework.shell.plugin.PromptProvider;
* @author Ben Alex
* @since 1.1
*/
public class JLineShellComponent extends JLineShell implements Lifecycle {
public class JLineShellComponent extends JLineShell implements SmartLifecycle, ApplicationContextAware, InitializingBean {
private volatile boolean running = false;
private Thread shellThread;
@@ -59,15 +63,26 @@ public class JLineShellComponent extends JLineShell implements Lifecycle {
// Fields
private ExecutionStrategy executionStrategy = new SimpleExecutionStrategy(); //ProcessManagerHostedExecutionStrategy is not what i think we need outside of Roo.
private ExecutionStrategy executionStrategy = new SimpleExecutionStrategy();
private SimpleParser parser = new SimpleParser();
public SimpleParser getSimpleParser() {
return parser;
}
public boolean isAutoStartup() {
return false;
}
public void stop(Runnable callback) {
stop();
callback.run();
}
public int getPhase() {
return 1;
}
public void start() {
//customizePlug must run before start thread to take plugin's configuration into effect
customizePlugin();
@@ -87,6 +102,19 @@ public class JLineShellComponent extends JLineShell implements Lifecycle {
public boolean isRunning() {
return running;
}
public void afterPropertiesSet() {
Map<String, CommandMarker> commands = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, CommandMarker.class);
for (CommandMarker command : commands.values()) {
getSimpleParser().add(command);
}
Map<String, Converter> converters = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, Converter.class);
for (Converter converter : converters.values()) {
getSimpleParser().add(converter);
}
}
/**
* wait the shell command to complete by typing "quit" or "exit"

View File

@@ -20,6 +20,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -1041,6 +1042,12 @@ public class SimpleParser implements Parser {
}
}
}
public final Set<CommandMarker> getCommandMarkers() {
synchronized (mutex) {
return Collections.unmodifiableSet(commands);
}
}
public final void remove(final CommandMarker command) {
synchronized (mutex) {
@@ -1067,4 +1074,10 @@ public class SimpleParser implements Parser {
converters.remove(converter);
}
}
public final Set<Converter<?>> getConverters() {
synchronized (mutex) {
return Collections.unmodifiableSet(converters);
}
}
}

View File

@@ -0,0 +1,38 @@
package org.springframework.shell;
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.logging.Logger;
import junit.framework.Assert;
import org.junit.Test;
import org.springframework.shell.core.JLineShellComponent;
import org.springframework.shell.event.ShellStatus;
import org.springframework.shell.event.ShellStatus.Status;
import org.springframework.shell.support.logging.HandlerUtils;
public class BootstrapTest {
@Test
public void test() throws IOException, InterruptedException {
try {
Bootstrap bootstrap = new Bootstrap(null);
JLineShellComponent shell = bootstrap.getJLineShellComponent();
shell.start();
while (shell.getShellStatus().getStatus() != ShellStatus.Status.USER_INPUT) {
Thread.sleep(100);
}
Assert.assertEquals("Number of CommandMarkers is incorrect", 4, shell.getSimpleParser().getCommandMarkers().size());
Assert.assertEquals("Number of Converters is incorrect", 16, shell.getSimpleParser().getConverters().size());
shell.stop();
} catch (RuntimeException t) {
throw t;
} finally {
HandlerUtils.flushAllHandlers(Logger.getLogger(""));
}
}
}