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 }