001: package gnu.kawa.servlet;
002:
003: import gnu.text.*;
004: import gnu.mapping.*;
005: import gnu.expr.*;
006: import gnu.lists.PrintConsumer;
007: import java.io.*;
008: import gnu.xml.*;
009:
010: /** The server state for a browser-based "read-eval-print-loop" session. */
011:
012: public class ReplSession extends Writer {
013: Language language;
014: Environment penvironment;
015: QueueReader qreader;
016: InPort in_p;
017: OutBufferWriter err_p;
018: OutBufferWriter out_p;
019: OutBufferWriter prompt_p;
020: Future thread;
021:
022: StringBuffer outBuffer = new StringBuffer();
023: boolean outAvailable;
024:
025: void append1(char c) {
026: if (c == '\r' || c == '\n')
027: outBuffer.append("<br/>");
028: else
029: outBuffer.append(c);
030: }
031:
032: public void write(int c) {
033: synchronized (this ) {
034: append1((char) c);
035: }
036: }
037:
038: public void write(char[] cbuf, int off, int len) {
039: synchronized (this ) {
040: for (int i = 0; i < len; i++)
041: append1(cbuf[off + i]);
042: }
043: }
044:
045: public void write(String str, int off, int len) {
046: synchronized (this ) {
047: for (int i = 0; i < len; i++)
048: append1(str.charAt(off + i));
049: }
050: }
051:
052: public void flush() {
053: synchronized (this ) {
054: if (outBuffer.length() > 0)
055: outAvailable = true;
056: notify();
057: }
058: }
059:
060: public void close() {
061: flush();
062: }
063:
064: String grabOutput() {
065: synchronized (this ) {
066: return grabOutputRaw();
067: }
068: }
069:
070: String waitOutput() {
071: synchronized (this ) {
072: if (!outAvailable) {
073: try {
074: wait(30000);
075: } catch (Throwable ex) {
076: ex.printStackTrace();
077: }
078: }
079: String out = grabOutputRaw();
080: return out;
081: }
082: }
083:
084: String grabOutputRaw() {
085: String result = outBuffer.toString();
086: outBuffer.setLength(0);
087: outAvailable = false;
088: return result;
089: }
090:
091: public ReplSession() {
092: this (kawa.standard.Scheme.getInstance());
093: //this(gnu.xquery.lang.XQuery.getInstance());
094: }
095:
096: public ReplSession(Language language) {
097: if (Language.getDefaultLanguage() == null)
098: Language.setDefaults(language);
099: penvironment = Environment.getCurrent();
100: qreader = new QueueReader();
101:
102: out_p = new OutBufferWriter(this , 'O', Path
103: .valueOf("/dev/stdout"));
104: err_p = new OutBufferWriter(this , 'E', Path
105: .valueOf("/dev/stderr>"));
106: prompt_p = new OutBufferWriter(this , 'P', Path
107: .valueOf("/dev/prompt"));
108: in_p = new MyTtyInPort(qreader, Path.valueOf("/dev/stdin"),
109: out_p, this );
110:
111: thread = new Future(new kawa.repl(language), penvironment,
112: in_p, out_p, err_p);
113: thread.start();
114: }
115:
116: void appendInputLine(String line) {
117: qreader.append(line);
118: qreader.append('\n');
119: }
120:
121: void appendInput(String line) {
122: qreader.append(line);
123: }
124: }
125:
126: class MyTtyInPort extends TtyInPort {
127: ReplSession session;
128: OutBufferWriter prompt_p;
129:
130: public MyTtyInPort(Reader in, Path path, OutPort tie,
131: ReplSession session) {
132: super (in, path, tie);
133: this .session = session;
134: this .prompt_p = session.prompt_p;
135: }
136:
137: int pcount;
138:
139: public void lineStart(boolean revisited) throws java.io.IOException {
140: if (!revisited && prompter != null) {
141: try {
142: tie.freshLine();
143: Object prompt = prompter.apply1(this );
144: if (prompt != null) {
145: String string = prompt.toString();
146: if (string != null && string.length() > 0) {
147: synchronized (session) {
148: session.out_p.flushToSessionBuffer();
149: session.outBuffer
150: .append("<div class=\"interaction\"><span std=\"prompt\">");
151: prompt_p.write(string);
152: prompt_p.flushToSessionBuffer();
153: session.outBuffer
154: .append("</span><input std='input' value='' onchange='enterLine(this);'/></div>");
155: session.flush();
156: }
157: tie.clearBuffer();
158: promptEmitted = true;
159: }
160: }
161: } catch (Throwable ex) {
162: throw new java.io.IOException(
163: "Error when evaluating prompt:" + ex);
164: }
165: }
166: }
167: }
168:
169: class OutBufferWriter extends XMLPrinter {
170: ReplSession session;
171: /** Which port this is:
172: * 'O': output
173: * 'E': error
174: * 'p': prompt
175: */
176: char kind;
177: int nesting = 0;
178:
179: public OutBufferWriter(ReplSession session, char kind, Path path) {
180: super (session, true);
181: // setPath(path); // FIXME need to implement super.setPath
182: this .session = session;
183: this .kind = kind;
184: }
185:
186: public void startElement(Object type) {
187: nesting++;
188: super .startElement(type);
189: }
190:
191: public void endElement() {
192: nesting--;
193: super .endElement();
194: }
195:
196: final void flushToSessionBuffer() throws java.io.IOException {
197: bout.forcePrettyOutput();
198: }
199:
200: public void flush() {
201: if (nesting > 0)
202: return;
203: synchronized (session) {
204: if (kind == 'E')
205: session.outBuffer.append("<span std=\"error\">");
206: try {
207: flushToSessionBuffer();
208: } catch (IOException ex) {
209: throw new RuntimeException(ex.toString());
210: }
211: if (kind == 'E')
212: session.outBuffer.append("</span>");
213: session.flush();
214: }
215: }
216: }
|