diff --git a/samples/helloworld/spring-shell.log b/samples/helloworld/spring-shell.log new file mode 100644 index 00000000..4d5cc012 --- /dev/null +++ b/samples/helloworld/spring-shell.log @@ -0,0 +1,5 @@ +// Spring Roo UNKNOWN VERSION log opened at 2012-04-11 18:02:23 +date +system properties +quit +// Spring Roo UNKNOWN VERSION log closed at 2012-04-11 18:02:32 diff --git a/src/main/java/org/springframework/shell/Bootstrap.java b/src/main/java/org/springframework/shell/Bootstrap.java index 1a01d915..aae22b03 100644 --- a/src/main/java/org/springframework/shell/Bootstrap.java +++ b/src/main/java/org/springframework/shell/Bootstrap.java @@ -124,6 +124,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); diff --git a/src/main/java/org/springframework/shell/JLineShell.java b/src/main/java/org/springframework/shell/JLineShell.java index e5aa8a77..4be662d7 100644 --- a/src/main/java/org/springframework/shell/JLineShell.java +++ b/src/main/java/org/springframework/shell/JLineShell.java @@ -25,6 +25,10 @@ import jline.ANSIBuffer.ANSICodes; import jline.ConsoleReader; import jline.WindowsTerminal; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.roo.shell.AbstractShell; import org.springframework.roo.shell.CommandMarker; import org.springframework.roo.shell.ExitShellRequest; @@ -39,6 +43,7 @@ import org.springframework.roo.support.util.IOUtils; import org.springframework.roo.support.util.OsUtils; import org.springframework.roo.support.util.StringUtils; import org.springframework.shell.commands.HintCommands; +import org.springframework.shell.plugin.HistoryFileProvider; /** @@ -51,17 +56,20 @@ import org.springframework.shell.commands.HintCommands; * use reflection in order to avoid hard dependencies on Jansi. * * @author Ben Alex + * @author Jarred Li * @since 1.0 */ -public abstract class JLineShell extends AbstractShell implements CommandMarker, Shell, Runnable { +public abstract class JLineShell extends AbstractShell implements CommandMarker, Shell, Runnable, + ApplicationContextAware { // Constants private static final String ANSI_CONSOLE_CLASSNAME = "org.fusesource.jansi.AnsiConsole"; - private static final boolean JANSI_AVAILABLE = ClassUtils.isPresent(ANSI_CONSOLE_CLASSNAME, JLineShell.class.getClassLoader()); + private static final boolean JANSI_AVAILABLE = ClassUtils.isPresent(ANSI_CONSOLE_CLASSNAME, + JLineShell.class.getClassLoader()); private static final boolean APPLE_TERMINAL = Boolean.getBoolean("is.apple.terminal"); private static final char ESCAPE = 27; private static final String BEL = "\007"; - + //TODO make configurable private static final String COMMAND_LINE_PROMPT = "spring>"; @@ -77,6 +85,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, private final Map rowErasureMap = new HashMap(); private boolean shutdownHookFired = false; // ROO-1599 + private ApplicationContext applicatonContext; + public void run() { try { if (JANSI_AVAILABLE && OsUtils.isWindows()) { @@ -115,7 +125,7 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, // Try to build previous command history from the project's log try { - String logFileContents = FileCopyUtils.copyToString(new File("log.roo")); + String logFileContents = FileCopyUtils.copyToString(new File(getHistoryFileName())); String[] logEntries = logFileContents.split(StringUtils.LINE_SEPARATOR); // LIFO for (String logEntry : logEntries) { @@ -123,7 +133,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, reader.getHistory().addToHistory(logEntry); } } - } catch (IOException ignored) {} + } catch (IOException ignored) { + } flashMessageRenderer(); @@ -131,9 +142,10 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, flash(Level.FINE, "Spring Roo " + versionInfo(), Shell.WINDOW_TITLE_SLOT); - + //TODO make this configurable - logger.info("Welcome to Spring Shell. For assistance press " + completionKeys + " or type \"hint\" then hit ENTER."); + logger.info("Welcome to Spring Shell. For assistance press " + completionKeys + + " or type \"hint\" then hit ENTER."); String startupNotifications = getStartupNotifications(); if (StringUtils.hasText(startupNotifications)) { @@ -161,7 +173,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, exitShellRequest = success ? ExitShellRequest.NORMAL_EXIT : ExitShellRequest.FATAL_EXIT; } setShellStatus(Status.SHUTTING_DOWN); - } else { + } + else { // Normal RPEL processing promptLoop(); } @@ -191,15 +204,18 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, ANSIBuffer ansi = JLineLogHandler.getANSIBuffer(); if (path == null || "".equals(path)) { shellPrompt = ansi.yellow(COMMAND_LINE_PROMPT).toString(); - } else { + } + else { if (overrideStyle) { ansi.append(path); - } else { + } + else { ansi.cyan(path); } shellPrompt = ansi.yellow(" " + COMMAND_LINE_PROMPT).toString(); } - } else { + } + else { // The superclass will do for this non-ANSI terminal super.setPromptPath(path); } @@ -210,7 +226,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, private ConsoleReader createAnsiWindowsReader() throws Exception { // Get decorated OutputStream that parses ANSI-codes - final PrintStream ansiOut = (PrintStream) ClassUtils.forName(ANSI_CONSOLE_CLASSNAME, JLineShell.class.getClassLoader()).getMethod("out").invoke(null); + final PrintStream ansiOut = (PrintStream) ClassUtils.forName(ANSI_CONSOLE_CLASSNAME, + JLineShell.class.getClassLoader()).getMethod("out").invoke(null); WindowsTerminal ansiTerminal = new WindowsTerminal() { @Override public boolean isANSISupported() { @@ -228,9 +245,10 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, }; addShellStatusListener(statusListener); - return new ConsoleReader(new FileInputStream(FileDescriptor.in), new PrintWriter(new OutputStreamWriter(ansiOut, - // Default to Cp850 encoding for Windows console output (ROO-439) - System.getProperty("jline.WindowsTerminal.output.encoding", "Cp850"))), null, ansiTerminal); + return new ConsoleReader(new FileInputStream(FileDescriptor.in), new PrintWriter(new OutputStreamWriter( + ansiOut, + // Default to Cp850 encoding for Windows console output (ROO-439) + System.getProperty("jline.WindowsTerminal.output.encoding", "Cp850"))), null, ansiTerminal); } private void flashMessageRenderer() { @@ -252,7 +270,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, // Message has expired, so clear it toRemove.add(slot); doAnsiFlash(flashInfo.rowNumber, Level.ALL, ""); - } else { + } + else { // The expiration time for this message has not been reached, so preserve it doAnsiFlash(flashInfo.rowNumber, flashInfo.flashLevel, flashInfo.flashMessage); } @@ -290,7 +309,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, try { reader.printString(stg); reader.flushConsole(); - } catch (IOException ignored) {} + } catch (IOException ignored) { + } } return; @@ -309,7 +329,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, return; } flashInfo.flashMessageUntil = System.currentTimeMillis() + 1500; - } else { + } + else { // Display this message displayed until further notice if (flashInfo == null) { // Find a row for this new slot; we basically take the first line number we discover @@ -346,7 +367,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, ANSIBuffer buff = JLineLogHandler.getANSIBuffer(); if (APPLE_TERMINAL) { buff.append(ESCAPE + "7"); - } else { + } + else { buff.append(ANSICodes.save()); } @@ -360,7 +382,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, if (mostFurtherLeftColNumber == Integer.MAX_VALUE) { // There is nothing to erase - } else { + } + else { buff.append(ANSICodes.gotoxy(row, mostFurtherLeftColNumber)); buff.append(ANSICodes.clreol()); // Clear what was present on the line } @@ -369,7 +392,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, // They want the line blank; we've already achieved this if needed via the erasing above // Just need to record we no longer care about this line the next time doAnsiFlash is invoked rowErasureMap.remove(row); - } else { + } + else { if (shutdownHookFired) { return; // ROO-1599 } @@ -385,7 +409,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, } if (APPLE_TERMINAL) { buff.append(ESCAPE + "8"); - } else { + } + else { buff.append(ANSICodes.restore()); } @@ -393,7 +418,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, try { reader.printString(stg); reader.flushConsole(); - } catch (IOException ignored) {} + } catch (IOException ignored) { + } } public void promptLoop() { @@ -430,7 +456,7 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, private void openFileLogIfPossible() { try { - fileLog = new FileWriter("log.roo", true); + fileLog = new FileWriter(getHistoryFileName(), true); // First write, so let's record the date and time of the first user command fileLog.write("// Spring Roo " + versionInfo() + " log opened at " + df.format(new Date()) + "\n"); fileLog.flush(); @@ -438,6 +464,21 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, } } + private String getHistoryFileName() { + String historyFileName = null; + Map historyFileProviders = BeanFactoryUtils.beansOfTypeIncludingAncestors( + this.applicatonContext, HistoryFileProvider.class); + int order = Integer.MIN_VALUE; + for(HistoryFileProvider p : historyFileProviders.values()){ + if(p.getOrder() > order){ + order = p.getOrder(); + historyFileName = p.getHistoryFileName(); + } + } + historyFileName = (historyFileName == null)?"spring-shell.log":historyFileName; + return historyFileName; + } + @Override protected void logCommandToOutput(final String processedLine) { if (fileLog == null) { @@ -495,4 +536,8 @@ public abstract class JLineShell extends AbstractShell implements CommandMarker, Level flashLevel; int rowNumber; } + + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicatonContext = applicationContext; + } } diff --git a/src/main/java/org/springframework/shell/plugin/HistoryFileProvider.java b/src/main/java/org/springframework/shell/plugin/HistoryFileProvider.java new file mode 100644 index 00000000..936c5b1b --- /dev/null +++ b/src/main/java/org/springframework/shell/plugin/HistoryFileProvider.java @@ -0,0 +1,36 @@ +/* + * 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.plugin; + +import org.springframework.core.Ordered; + +/** + * To get history file name + * + * @author Jarred Li + * @since 1.0 + * + */ +public interface HistoryFileProvider extends Ordered{ + + /** + * get history file name + * + * @return history file name + */ + String getHistoryFileName(); + +} diff --git a/src/main/java/org/springframework/shell/plugin/support/DefaultHistoryFileProvider.java b/src/main/java/org/springframework/shell/plugin/support/DefaultHistoryFileProvider.java new file mode 100644 index 00000000..c7814fdd --- /dev/null +++ b/src/main/java/org/springframework/shell/plugin/support/DefaultHistoryFileProvider.java @@ -0,0 +1,43 @@ +/* + * 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.plugin.support; + +import org.springframework.core.Ordered; +import org.springframework.shell.plugin.HistoryFileProvider; +import org.springframework.stereotype.Component; + +/** + * @author Jarred Li + * + */ +@Component +public class DefaultHistoryFileProvider implements HistoryFileProvider{ + + /* (non-Javadoc) + * @see org.springframework.core.Ordered#getOrder() + */ + public int getOrder() { + return 0; + } + + /* (non-Javadoc) + * @see org.springframework.shell.plugin.HistoryFileProvider#getHistoryFileName() + */ + public String getHistoryFileName() { + return "spring-shell.log"; + } + +}