SHL-86 - Change bootstrapping procedure so JLineShellComponent can resolve its own dependencies.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ target/
|
||||
/log.roo
|
||||
|
||||
/bin/
|
||||
/*.log
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
src/test/java/org/springframework/shell/BootstrapTest.java
Normal file
38
src/test/java/org/springframework/shell/BootstrapTest.java
Normal 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(""));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user