001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.geronimo.gshell.console;
021    
022    import java.io.IOException;
023    
024    import org.slf4j.Logger;
025    import org.slf4j.LoggerFactory;
026    
027    /**
028     * Provides an abstraction of a console.
029     *
030     * @version $Rev: 573669 $ $Date: 2007-09-07 11:47:20 -0700 (Fri, 07 Sep 2007) $
031     */
032    public abstract class Console
033        implements Runnable
034    {
035        protected final Logger log = LoggerFactory.getLogger(getClass());
036    
037        protected boolean running = false;
038    
039        protected boolean breakOnNull = true;
040    
041        protected boolean autoTrim = true;
042    
043        protected boolean ignoreEmpty = true;
044    
045        protected Prompter prompter = new Prompter() {
046            public String prompt() {
047                return "> ";
048            }
049        };
050    
051        protected Executor executor;
052    
053        protected ErrorHandler errorHandler = new ErrorHandler() {
054            public Result handleError(Throwable error) {
055                return Result.STOP;
056            }
057        };
058    
059        public Console(final Executor executor) {
060            assert executor != null;
061    
062            this.executor = executor;
063        }
064    
065        public boolean isRunning() {
066            return running;
067        }
068    
069        public void setRunning(final boolean running) {
070            this.running = running;
071        }
072    
073        public boolean isBreakOnNull() {
074            return breakOnNull;
075        }
076    
077        public void setBreakOnNull(final boolean breakOnNull) {
078            this.breakOnNull = breakOnNull;
079        }
080    
081        public boolean isAutoTrim() {
082            return autoTrim;
083        }
084    
085        public void setAutoTrim(final boolean autoTrim) {
086            this.autoTrim = autoTrim;
087        }
088    
089        public boolean isIgnoreEmpty() {
090            return ignoreEmpty;
091        }
092    
093        public void setIgnoreEmpty(final boolean ignoreEmpty) {
094            this.ignoreEmpty = ignoreEmpty;
095        }
096    
097        public ErrorHandler getErrorHandler() {
098            return errorHandler;
099        }
100    
101        public void setErrorHandler(final ErrorHandler errorHandler) {
102            this.errorHandler = errorHandler;
103        }
104    
105        public Prompter getPrompter() {
106            return prompter;
107        }
108    
109        public void setPrompter(final Prompter prompter) {
110            this.prompter = prompter;
111        }
112    
113        public Executor getExecutor() {
114            return executor;
115        }
116    
117        public void setExecutor(final Executor executor) {
118            this.executor = executor;
119        }
120    
121        public void run() {
122            log.debug("Running");
123    
124            running = true;
125    
126            while (running) {
127                try {
128                    running = work();
129                }
130                catch (Throwable t) {
131                    // Don't use {} here so we get the throwable detail in the log stream
132                    log.debug("Work failed: " + t, t);
133                    
134                    if (errorHandler != null) {
135                        ErrorHandler.Result result = errorHandler.handleError(t);
136    
137                        // Allow the error handler to request that the loop stop
138                        if (result == ErrorHandler.Result.STOP) {
139                            log.debug("Error handler requested STOP");
140                            running = false;
141                        }
142                    }
143                }
144            }
145    
146            log.debug("Finished");
147        }
148    
149        protected boolean work() throws Exception {
150            String line = readLine(prompter.prompt());
151    
152            log.debug("Read line: {}", line);
153    
154            // Log the line as HEX if trace is enabled
155            if (log.isTraceEnabled()) {
156                StringBuffer idx = new StringBuffer();
157                StringBuffer hex = new StringBuffer();
158    
159                byte[] bytes = line.getBytes();
160                for (byte b : bytes) {
161                    String h = Integer.toHexString(b);
162    
163                    hex.append("x").append(h).append(" ");
164                    idx.append(" ").append((char)b).append("  ");
165                }
166    
167                log.trace("HEX: {}", hex);
168                log.trace("     {}", idx);
169            }
170    
171            // Stop on null (maybe, else ignore)
172            if (line == null) {
173                return !breakOnNull;
174            }
175    
176            // Auto trim the line (maybe)
177            if (autoTrim) {
178                line = line.trim();
179            }
180    
181            // Ingore empty lines (maybe)
182            if (ignoreEmpty && line.length() == 0) {
183                return true;
184            }
185    
186            // Execute the line
187            Executor.Result result = executor.execute(line);
188    
189            // Allow executor to request that the loop stop
190            if (result == Executor.Result.STOP) {
191                log.debug("Executor requested STOP");
192                return false;
193            }
194    
195            return true;
196        }
197    
198        protected abstract String readLine(String prompt) throws IOException;
199    
200        //
201        // Prompter
202        //
203    
204        public static interface Prompter
205        {
206            String prompt();
207        }
208    
209        //
210        // Executor
211        //
212    
213        public static interface Executor
214        {
215            enum Result {
216                CONTINUE,
217                STOP
218            }
219    
220            Result execute(String line) throws Exception;
221        }
222    
223        //
224        // ErrorHandler
225        //
226    
227        public static interface ErrorHandler
228        {
229            enum Result {
230                CONTINUE,
231                STOP
232            }
233            
234            Result handleError(Throwable error);
235        }
236    }