package org.codehaus.mojo.pomtools.console.toolkit; /* * Copyright 2005-2006 The Apache Software Foundation. * * 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. */ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.codehaus.mojo.pomtools.console.toolkit.event.ConsoleEventDispatcher; import org.codehaus.mojo.pomtools.console.toolkit.terminal.Terminal; import org.codehaus.mojo.pomtools.helpers.LocalStringUtils; /** * * @author <a href="mailto:dhawkins@codehaus.org">David Hawkins</a> * @version $Id$ */ public class ConsoleApp { private final Terminal terminal; private final InitialState initialState; private static final String NEWLINE = "\n"; private LinkedList screens; private static ThreadLocal threadLocal = new ThreadLocal(); public ConsoleApp( Terminal terminal, InitialState initialState ) { this.terminal = terminal; this.initialState = initialState; initialize(); } protected void initialize() { this.screens = new LinkedList(); screens.add( initialState.getInitialScreen() ); } /** Returns the ThreadLocal instance of this ConsoleApp. You must * call {@link #setCurrent(ConsoleApp)} before calling this function. * @throws IllegalStateException if the current connection is not set */ public static ConsoleApp getCurrent() { ConsoleApp app = (ConsoleApp) threadLocal.get(); if ( app == null ) { throw new IllegalStateException( "ConsoleApp in the thread-local variable was null, " + "please call setCurrent() first" ); } return app; } /** Sets the ThreadLocal ConsoleApp instance. See {@see #getCurrent} for more information. */ public static void setCurrent( ConsoleApp app ) { threadLocal.set( app ); } public static boolean hasCurrent() { return threadLocal.get() != null; } public void execute() throws ConsoleExecutionException { ConsoleScreen screen = null; ConsoleScreenDisplay display = null; ConsoleScreenDisplay previousDisplay = null; List consoleMessages = null; while ( true ) { screen = (ConsoleScreen) screens.getLast(); ConsoleEventDispatcher dispatcher = screen.getEventDispatcher(); previousDisplay = display; display = screen.getDisplay(); drawScreenContents( display, consoleMessages, previousDisplay ); // Now that we have used it, reset it back to null consoleMessages = null; ConsoleEvent event = new ConsoleEvent( terminal, terminal.readLine() ); // Now make our screen handle the event. dispatcher.dispatchEvent( event ); // Now see what action (if any) we need to take on the result if ( !event.isConsumed() ) { event.addConsoleMessage( "Your response was not understood, please try again." ); } if ( event.getConsoleMessages() != null && !event.getConsoleMessages().isEmpty() ) { consoleMessages = event.getConsoleMessages(); } if ( event.isExitApplication() ) { break; } else if ( event.isReturnToFirstScreen() ) { initialize(); } else if ( event.isReturnToPreviousScreen() ) { if ( screens.size() > 1 ) { screens.removeLast(); } } else if ( event.getNextScreen() != null ) { screens.add( event.getNextScreen() ); } } } private void drawScreenContents( ConsoleScreenDisplay display, List consoleMessages, ConsoleScreenDisplay previousDisplay ) throws ConsoleExecutionException { if ( terminal.supportsClearScreen() && display.isRedrawPreviousContents() ) { display.setContents( previousDisplay.getContents() ); } if ( terminal.supportsClearScreen() && display.isClearScreen() ) { terminal.clearScreen(); } StringBuffer sb = new StringBuffer(); if ( display.getContents() != null ) { sb.append( LocalStringUtils.makeEndWith( display.getContents(), NEWLINE ) ); sb.append( NEWLINE ); } if ( consoleMessages != null ) { for ( Iterator iter = consoleMessages.iterator(); iter.hasNext(); ) { sb.append( LocalStringUtils.makeEndWith( terminal.bold( "<< " + (String) iter.next() ), NEWLINE ) ); } } sb.append( display.getPrompt() ); sb.append( " " ); terminal.write( sb.toString() ); } public Terminal getTerminal() { return terminal; } public interface InitialState { ConsoleScreen getInitialScreen(); } }