001: // Copyright (c) 2002. 2006 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.kawa.xml;
005:
006: import gnu.lists.*;
007: import gnu.xml.*;
008: import java.io.*;
009: import gnu.mapping.*;
010: import java.util.Vector;
011:
012: /** Output as an Http response.
013: * Used for both CGI scripts (default) and HttpServletResponse (future).
014: */
015:
016: public class HttpPrinter extends FilterConsumer {
017: Vector headers = new Vector();
018: /* #ifdef JAVA5 */
019: // StringBuilder sbuf = new StringBuilder(100);
020: /* #else */
021: StringBuffer sbuf = new StringBuffer(100);
022: /* #endif */
023: Object currentHeader;
024:
025: /** 1 - implicit; 2: explicit. */
026: private int seenStartDocument;
027:
028: protected String sawContentType;
029:
030: /** Difference between number of startElement and endElement calls so far. */
031: private int elementNesting;
032:
033: protected OutputStream ostream;
034: OutPort writer;
035:
036: public HttpPrinter(OutputStream out) {
037: super (null);
038: ostream = out;
039: //ostream = System.out;
040: }
041:
042: public HttpPrinter(OutPort out) {
043: super (null);
044: writer = out;
045: //ostream = System.out;
046: }
047:
048: public static HttpPrinter make(OutPort out) {
049: return new HttpPrinter(out);
050: }
051:
052: private void writeRaw(String str) throws java.io.IOException {
053: if (writer != null)
054: writer.write(str);
055: else {
056: int len = str.length();
057: for (int i = 0; i < len; i++)
058: ostream.write((byte) str.charAt(i));
059: }
060: }
061:
062: public void printHeader(String label, String value)
063: throws java.io.IOException {
064: writeRaw(label);
065: writeRaw(": ");
066: writeRaw(value); // FIXME - need to quote?
067: writeRaw("\n");
068: }
069:
070: public void printHeaders() throws java.io.IOException {
071: int num = headers.size();
072: for (int i = 0; i < num; i += 2)
073: printHeader(headers.elementAt(i).toString(), headers
074: .elementAt(i + 1).toString());
075: // if (sawContentType == null) writeRaw("Content-Type: text/html"); FIXME
076: writeRaw("\n");
077: }
078:
079: public void addHeader(String label, String value) {
080: if (label.equalsIgnoreCase("Content-type"))
081: sawContentType = value;
082: headers.addElement(label);
083: headers.addElement(value);
084: }
085:
086: public void startAttribute(Object attrType) {
087: if (base == null)
088: currentHeader = attrType;
089: else
090: base.startAttribute(attrType);
091: }
092:
093: public void endAttribute() {
094: if (currentHeader != null) {
095: addHeader(currentHeader.toString(), sbuf.toString());
096: sbuf.setLength(0);
097: currentHeader = null;
098: } else
099: base.endAttribute();
100: }
101:
102: boolean seenXmlHeader;
103:
104: public void beginData() {
105: if (base == null) {
106: if (sawContentType == null)
107: addHeader("Content-type", "text/html");
108: if (writer == null)
109: writer = new OutPort(ostream); // FIXME use encoding.
110: String style = null;
111: if ("text/html".equalsIgnoreCase(sawContentType))
112: style = "html";
113: else if ("text/xhtml".equalsIgnoreCase(sawContentType))
114: style = "xhtml";
115: else if ("text/plain".equalsIgnoreCase(sawContentType))
116: style = "plain";
117: base = XMLPrinter.make(writer, style);
118: if (seenStartDocument == 0) {
119: base.startDocument();
120: seenStartDocument = 1;
121: }
122: try {
123: printHeaders();
124: } catch (Throwable ex) {
125: throw new RuntimeException(ex.toString());
126: }
127: }
128: /* #ifdef use:java.lang.CharSequence */
129: append(sbuf);
130: /* #else */
131: // write(sbuf.toString());
132: /* #endif */
133: sbuf.setLength(0);
134: }
135:
136: public void startElement(Object type) {
137: if (sawContentType == null) {
138: String mimeType;
139: if (!seenXmlHeader)
140: mimeType = "text/html";
141: else if (type instanceof Symbol
142: && "html".equals(((Symbol) type).getLocalPart()))
143: mimeType = "text/xhtml";
144: else
145: mimeType = "text/xml";
146: addHeader("Content-type", mimeType);
147: }
148: beginData();
149: base.startElement(type);
150: elementNesting++;
151: }
152:
153: public void endElement() {
154: super .endElement();
155: elementNesting--;
156: if (elementNesting == 0 && seenStartDocument == 1)
157: endDocument();
158: }
159:
160: public void writeObject(Object v) {
161: if (v instanceof Consumable && !(v instanceof UnescapedData))
162: ((Consumable) v).consume(this );
163: else {
164: beginData();
165: super .writeObject(v);
166: }
167: }
168:
169: /* #ifdef use:java.lang.CharSequence */
170: public Consumer append(CharSequence csq, int start, int end) {
171: if (base == null) {
172: /* #ifdef JAVA5 */
173: // sbuf.append(csq, start, end);
174: /* #else */
175: if (csq == null)
176: csq = "null";
177: sbuf.append(csq.subSequence(start, end).toString());
178: /* #endif */
179: } else
180: base.write(csq, start, end);
181: return this ;
182: }
183:
184: public Consumer append(CharSequence csq) {
185: if (base == null) {
186: /* #ifdef JAVA5 */
187: // sbuf.append(csq);
188: /* #else */
189: sbuf.append(csq.toString());
190: /* #endif */
191: } else if (csq == null)
192: base.write("null");
193: else
194: base.write(csq, 0, csq.length());
195: return this ;
196: }
197:
198: /* #endif */
199:
200: public void write(char[] buf, int off, int len) {
201: if (base == null)
202: sbuf.append(buf, off, len);
203: else
204: base.write(buf, off, len);
205: }
206:
207: public void startDocument() {
208: if (base != null)
209: base.startDocument();
210: seenStartDocument = 2;
211: }
212:
213: public void endDocument() {
214: if (base != null)
215: base.endDocument();
216: try {
217: // else ???;
218: if (writer != null)
219: writer.close();
220: if (ostream != null)
221: ostream.flush();
222: } catch (Throwable ex) {
223: }
224: }
225: }
|