001: /*
002: * This is free software, licensed under the Gnu Public License (GPL)
003: * get a copy from <http://www.gnu.org/licenses/gpl.html>
004: * $Id: SpoolCommand.java,v 1.6 2005/06/18 04:58:13 hzeller Exp $
005: * author: Henner Zeller <H.Zeller@acm.org>
006: */
007: package henplus.commands;
008:
009: import henplus.SQLSession;
010: import henplus.HenPlus;
011: import henplus.AbstractCommand;
012: import henplus.OutputDevice;
013: import henplus.PrintStreamOutputDevice;
014:
015: import java.util.Stack;
016: import java.util.Date;
017: import java.io.PrintStream;
018: import java.io.FileOutputStream;
019: import java.io.IOException;
020:
021: /**
022: * prepared ..
023: */
024: public final class SpoolCommand extends AbstractCommand {
025: private final Stack/*<OutputDevice>*/_outStack;
026: private final Stack/*<OutputDevice>*/_msgStack;
027:
028: /**
029: * returns the command-strings this command can handle.
030: */
031: public String[] getCommandList() {
032: return new String[] { "spool" };
033: }
034:
035: public SpoolCommand(HenPlus hp) {
036: _outStack = new Stack/*<OutputDevice>*/();
037: _msgStack = new Stack/*<OutputDevice>*/();
038: _outStack.push(hp.getOutputDevice());
039: _msgStack.push(hp.getMessageDevice());
040: }
041:
042: public boolean requiresValidSession(String cmd) {
043: return false;
044: }
045:
046: /**
047: * execute the command given.
048: */
049: public int execute(SQLSession currentSession, String cmd,
050: String param) {
051: param = param.trim();
052: try {
053: if ("off".equals(param.toLowerCase())) {
054: closeSpool();
055: } else if (param.length() > 0) {
056: openSpool(param);
057: } else {
058: return SYNTAX_ERROR;
059: }
060: } catch (Exception e) {
061: e.printStackTrace();
062: return EXEC_FAILED;
063: }
064: return SUCCESS;
065: }
066:
067: /**
068: * combine the current output from the stack with the given output,
069: * use this as current output and return it.
070: */
071: private OutputDevice openStackedDevice(
072: Stack/*<OutputDevice>*/stack, OutputDevice newOut) {
073: OutputDevice origOut = (OutputDevice) stack.peek();
074: OutputDevice outDevice = new StackedDevice(origOut, newOut);
075: stack.push(outDevice);
076: return outDevice;
077: }
078:
079: /**
080: * close the top device on the stack and return the previous.
081: */
082: private OutputDevice closeStackedDevice(
083: Stack/*<OutputDevice>*/stack) {
084: OutputDevice out = (OutputDevice) stack.pop();
085: out.close();
086: return (OutputDevice) stack.peek();
087: }
088:
089: private void openSpool(String filename) throws IOException {
090: // open file
091: OutputDevice spool = new PrintStreamOutputDevice(
092: new PrintStream(new FileOutputStream(filename)));
093: HenPlus.getInstance().setOutput(
094: openStackedDevice(_outStack, spool),
095: openStackedDevice(_msgStack, spool));
096: HenPlus.msg().println("-- open spool at " + new Date());
097: }
098:
099: private boolean closeSpool() throws IOException {
100: if (_outStack.size() == 1) {
101: HenPlus.msg().println("no open spool.");
102: return false;
103: }
104: HenPlus.msg().println("-- close spool at " + new Date());
105: HenPlus.getInstance().setOutput(closeStackedDevice(_outStack),
106: closeStackedDevice(_msgStack));
107: return true;
108: }
109:
110: public String getShortDescription() {
111: return "log output to a file";
112: }
113:
114: public String getSynopsis(String cmd) {
115: return "spool <filename>|off";
116: }
117:
118: public String getLongDescription(String cmd) {
119: String dsc;
120: dsc = "\tIf command is followed by a filename, opens a file\n"
121: + "\tand writes all subsequent output not only to the terminal\n"
122: + "\tbut as well to this file. With\n"
123: + "\t spool off\n"
124: + "\tspooling is stopped and the file is closed. The spool\n"
125: + "\tcommand works recursivly, i.e. you can open more than one \n"
126: + "\tfile, and you have to close each of them with 'spool off'\n";
127: return dsc;
128: }
129:
130: /**
131: * A stream that writes to two output streams. On close, only
132: * the second, stacked stream is closed.
133: */
134: private static class StackedDevice implements OutputDevice {
135: private final OutputDevice _a;
136: private final OutputDevice _b;
137:
138: public StackedDevice(OutputDevice a, OutputDevice b) {
139: _a = a;
140: _b = b;
141: }
142:
143: public void flush() {
144: _a.flush();
145: _b.flush();
146: }
147:
148: public void write(byte[] buffer, int off, int len) {
149: _a.write(buffer, off, len);
150: _b.write(buffer, off, len);
151: }
152:
153: public void print(String s) {
154: _a.print(s);
155: _b.print(s);
156: }
157:
158: public void println(String s) {
159: _a.println(s);
160: _b.println(s);
161: }
162:
163: public void println() {
164: _a.println();
165: _b.println();
166: }
167:
168: public void attributeBold() {
169: _a.attributeBold();
170: _b.attributeBold();
171: }
172:
173: public void attributeGrey() {
174: _a.attributeGrey();
175: _b.attributeGrey();
176: }
177:
178: public void attributeReset() {
179: _a.attributeReset();
180: _b.attributeReset();
181: }
182:
183: /** closes _only_ the (stacked) second stream */
184: public void close() {
185: _b.close();
186: }
187:
188: public boolean isTerminal() {
189: return _a.isTerminal() && _b.isTerminal();
190: }
191: }
192: }
193:
194: /*
195: * Local variables:
196: * c-basic-offset: 4
197: * compile-command: "ant -emacs -find build.xml"
198: * End:
199: */
|