001: /* ****************************************************************************
002: * SOAPDataEncoder.java
003: *
004: * Compile XML to JSON which will tell the LFC to build a LzDataElement DOM strucure
005: * ****************************************************************************/
006:
007: /* J_LZ_COPYRIGHT_BEGIN *******************************************************
008: * Copyright 2001-2007 Laszlo Systems, Inc. All Rights Reserved. *
009: * Use is subject to license terms. *
010: * J_LZ_COPYRIGHT_END *********************************************************/
011:
012: package org.openlaszlo.remote.json.soap.encoding;
013:
014: import java.io.*;
015: import java.util.*;
016: import java.util.Iterator;
017:
018: import javax.xml.namespace.QName;
019: import javax.xml.soap.Name;
020: import javax.xml.soap.SOAPElement;
021:
022: import org.openlaszlo.remote.json.soap.ObjectWrapper;
023: import org.apache.xml.serialize.XMLSerializer;
024: import org.apache.xml.serialize.OutputFormat;
025: import org.openlaszlo.server.LPS;
026: import org.openlaszlo.remote.json.soap.LZSOAPUtils;
027: import org.openlaszlo.utils.ChainedException;
028: import org.openlaszlo.xml.internal.DataCommon;
029: import org.openlaszlo.xml.internal.DataContext;
030: import org.openlaszlo.sc.ScriptCompiler;
031: import org.apache.axis.AxisFault;
032: import org.apache.log4j.Logger;
033: import org.xml.sax.*;
034: import org.xml.sax.helpers.AttributesImpl;
035:
036: import org.apache.axis.message.MessageElement;
037: import org.apache.axis.message.SOAPHeader;
038: import org.apache.axis.message.Text;
039:
040: /**
041: */
042: public class SOAPDataEncoder implements ContentHandler {
043:
044: /* Logger */
045: private static Logger mLogger = Logger
046: .getLogger(SOAPDataEncoder.class);
047:
048: private StringBuffer body = new StringBuffer();
049: private StringBuffer headers = new StringBuffer();
050:
051: /**
052: * Constructs an empty SOAPDataEncoder.
053: */
054: public SOAPDataEncoder() {
055: body = new StringBuffer();
056: headers = new StringBuffer();
057: }
058:
059: /**
060: * Workaround variable for bug 4680.
061: */
062: boolean isProgram = false;
063:
064: public SOAPDataEncoder(Vector v, SOAPHeader h) {
065: body = new StringBuffer();
066: headers = new StringBuffer();
067:
068: buildFromElements(v, h);
069: }
070:
071: public SOAPDataEncoder(Object p, SOAPHeader h) {
072: body = new StringBuffer();
073: headers = new StringBuffer();
074: buildFromProgram(p, h);
075: }
076:
077: public SOAPDataEncoder buildFromFault(AxisFault fault) {
078: start();
079: String actor = fault.getFaultActor(); // can be null
080: QName code = fault.getFaultCode(); // can be null
081: String node = fault.getFaultNode(); // SOAP1.2
082: String reason = fault.getFaultReason(); // SOAP1.2==SOAP1.1 faultstring
083: String role = fault.getFaultRole(); // SOAP1.2==SOAP1.1 actor
084: String faultstring = fault.getFaultString(); // never null
085: QName[] subcodes = fault.getFaultSubCodes(); // can be null
086: // Element[] details = fault.getFaultDetails(); // can be null
087: // ArrayList headers = fault.getHeaders();
088:
089: body.append("{");
090:
091: // +++ TODO [hqm 2007-03-08] should there be a key string like "subcodes" pushed here??
092:
093: int items = 0;
094: if (subcodes != null) {
095: body.append("subcodes: ");
096: body.append("[");
097: for (int i = 0; i < subcodes.length; i++) {
098: if (i > 0) {
099: body.append(",");
100: }
101: QName qname = subcodes[i];
102: if (qname == null) {
103: body.append("null");
104: } else {
105: body.append("new QName("
106: + ScriptCompiler
107: .quote(qname.getLocalPart())
108: + ", "
109: + ScriptCompiler.quote(qname
110: .getNamespaceURI()) + ")");
111: }
112: }
113: body.append("]");
114: items++;
115: }
116:
117: if (actor != null) {
118: body.append(items > 0 ? "," : "");
119: body.append("actor: " + ScriptCompiler.quote(actor));
120: items++;
121: }
122: if (node != null) {
123: body.append(items > 0 ? "," : "");
124: body.append("node: " + ScriptCompiler.quote(node));
125: items++;
126: }
127:
128: if (reason != null) {
129: body.append(items > 0 ? "," : "");
130: body.append("reason: " + ScriptCompiler.quote(reason));
131: items++;
132: }
133:
134: if (role != null) {
135: body.append(items > 0 ? "," : "");
136: body.append("role: " + ScriptCompiler.quote(role));
137: items++;
138: }
139:
140: if (faultstring != null) {
141: body.append(items > 0 ? "," : "");
142: body.append("faultstring: "
143: + ScriptCompiler.quote(faultstring));
144: items++;
145: }
146:
147: if (code != null) {
148: body.append(items > 0 ? "," : "");
149: body.append("code: " + "new QName("
150: + ScriptCompiler.quote(code.getLocalPart()) + ", "
151: + ScriptCompiler.quote(code.getNamespaceURI())
152: + ")");
153: items++;
154: }
155:
156: body.append(items > 0 ? "," : "");
157: body.append("errortype: " + ScriptCompiler.quote("fault"));
158: body.append("}");
159: end();
160:
161: return this ;
162: }
163:
164: public SOAPDataEncoder buildFromException(Exception e) {
165: start();
166: {
167: Throwable cause = e.getCause();
168: String message = e.getMessage();
169: StringWriter sw = new StringWriter();
170: e.printStackTrace(new PrintWriter(sw));
171:
172: int count = 3;
173: body.append("{");
174: body.append("stacktrace: "
175: + ScriptCompiler.quote(sw.toString()));
176:
177: body.append(",faultString: ");
178: if (message != null) {
179: body.append(ScriptCompiler.quote(message));
180: } else {
181: ScriptCompiler.quote(sw.toString());
182: }
183:
184: if (cause != null) {
185: body.append(",cause: ");
186: body.append(ScriptCompiler.quote(cause.toString()));
187: }
188:
189: body.append(", errortype: ");
190: body.append(ScriptCompiler.quote("exception"));
191:
192: body.append("}");
193: }
194: end();
195: return this ;
196: }
197:
198: public void startElement(String localName, Attributes atts) {
199: }
200:
201: public void startElement(String uri, String localName,
202: String qName, Attributes atts) {
203: }
204:
205: public void start() {
206: body = new StringBuffer();
207: headers = new StringBuffer();
208: }
209:
210: public void end() {
211: }
212:
213: public void endElement(String uri, String localName, String qName) {
214: }
215:
216: public void endElement() {
217: }
218:
219: private void buildHeaders(SOAPHeader h) throws IOException {
220: int hCount = 0;
221: Iterator iter = h.getChildElements();
222: StringBuffer buf = new StringBuffer();
223: buf.append("[");
224:
225: while (iter.hasNext()) {
226: SOAPElement elt = (SOAPElement) iter.next();
227: String str = serializeSOAPElt(elt);
228: buf.append(ScriptCompiler.quote(str));
229: if (hCount++ > 0) {
230: buf.append(",");
231: }
232: }
233: buf.append("]");
234:
235: if (hCount != 0) {
236: headers.append(buf.toString());
237: } else {
238: headers.append("null");
239: }
240: }
241:
242: private String serializeSOAPElt(SOAPElement elem)
243: throws IOException {
244: return elem.toString();
245: /*
246: StringWriter outbuf = new StringWriter();
247: XMLSerializer xser = new XMLSerializer(outbuf, new OutputFormat());
248: xser.serialize(elem);
249: String str = outbuf.toString();
250: return str;
251: */
252: }
253:
254: /**
255: * Build from a vector of SOAPElement items.
256: *
257: * @param v vector of SOAPElement items.
258: */
259: public void buildFromElements(Vector v, SOAPHeader h) {
260: try {
261: startDocument();
262:
263: // soap headers
264: buildHeaders(h);
265:
266: //LzDataNode.stringToLzData
267: // array of documents
268: int count = 0;
269:
270: if (v.size() != 1) {
271: throw new RuntimeException(
272: "SOAPDataEncoder.buildFromElements expected just one value, got "
273: + v.size() + " " + v);
274: }
275:
276: SOAPElement elem = ((SOAPElement) v.get(0));
277: String str = serializeSOAPElt(elem);
278: body.append("LzDataNode.stringToLzData("
279: + ScriptCompiler.quote(str) + ")");
280:
281: endDocument();
282: } catch (IOException e) {
283: throw new RuntimeException(e.getMessage());
284: }
285: }
286:
287: /**
288: * Build from a vector of SOAPElement items.
289: *
290: * @param p an Object value, already coerced to a string
291: */
292: public void buildFromProgram(Object p, SOAPHeader h) {
293: if (p == null) {
294: mLogger
295: .debug("json.SOAPDataEncoder buildFromProgram p=null");
296: body = new StringBuffer("null");
297: return;
298: }
299: if (p instanceof String) {
300: mLogger
301: .debug("json.SOAPDataEncoder buildFromProgram p=String "
302: + p);
303: body = new StringBuffer(p.toString());
304: } else {
305: mLogger
306: .debug("json.SOAPDataEncoder buildFromProgram p.getClass()="
307: + p.getClass());
308: body = new StringBuffer(encodeArray(p));
309: }
310: }
311:
312: String encodeArray(Object obj) {
313: Object[] p = (Object[]) obj;
314: StringBuffer buf = new StringBuffer();
315: buf.append("[");
316: for (int i = 0; i < p.length; i++) {
317: if (i > 0)
318: buf.append(",");
319: buf.append(encodeObject(p[i]));
320: }
321: buf.append("]");
322: return buf.toString();
323: }
324:
325: String encodeObject(Object p) {
326: try {
327: if (p instanceof ObjectWrapper) {
328: org.w3c.dom.Element e = (((ObjectWrapper) p)
329: .getElement());
330: return serializeSOAPElt((SOAPElement) e);
331: } else if (p.getClass().isArray()) {
332: return encodeArray((Object[]) p);
333: } else {
334: return p.toString();
335: }
336: } catch (java.io.IOException e) {
337: return e.getMessage();
338: }
339: }
340:
341: /**
342: * End the scope of a prefix-URI mapping. This method is unimplemented.
343: *
344: * @param prefix the prefix that was being mapped.
345: */
346: public void endPrefixMapping(String prefix) {
347: }
348:
349: public void characters(char[] ch, int start, int length) {
350: }
351:
352: public void characters(String text) {
353: }
354:
355: /**
356: * Receive notification of ignorable whitespace in element content. This
357: * method is unimplemented.
358: *
359: * @param ch the characters from the XML document.
360: * @param start the start position in the array.
361: * @param length the number of characters to read from the array.
362: */
363: public void ignorableWhitespace(char[] ch, int start, int length) {
364: }
365:
366: /**
367: * Receive notification of a processing instruction. This method is
368: * unimplemented.
369: *
370: * @param target the processing instruction target.
371: * @param data the processing instruction data, or null if none was
372: * supplied. The data does not include any whitespace separating it from the
373: * target.
374: */
375: public void processingInstruction(String target, String data) {
376: }
377:
378: /**
379: * Receive an object for locating the origin of SAX document events. This
380: * method is unimplemented.
381: *
382: * @param locator an object that can return the location of any SAX document
383: * event.
384: */
385: public void setDocumentLocator(Locator locator) {
386: }
387:
388: /**
389: * Receive notification of a skipped entity. This method is unimplemented.
390: *
391: * @param name the name of the skipped entity. If it is a parameter entity,
392: * the name will begin with '%', and if it is the external DTD subset, it
393: * will be the string "[dtd]".
394: */
395: public void skippedEntity(String name) {
396: }
397:
398: public void startPrefixMapping(String prefix, String uri) {
399: }
400:
401: public void startDocument() {
402: }
403:
404: public void endDocument() {
405: end();
406: }
407:
408: public InputStream getInputStream() {
409: // String bodyplusheaders = "["+headers.toString()+","+body.toString()+"]";
410:
411: // TODO [hqm 4-9-2007] Need to figure out how to pass headers; the xmlrpc and javarpc
412: // code needs to be modified to pass headers also, then it can go as a list of
413: // [data, headers], and the client in rpc/library.dhtml/rpc.js will separate it out.
414: String bodystr = body.toString();
415: return new StringBufferInputStream(bodystr);
416: }
417:
418: /**
419: */
420: public long getSize() {
421: //String bodyplusheaders = "["+headers.toString()+","+body.toString()+"]";
422: String bodystr = body.toString();
423: return bodystr.length();
424: }
425:
426: }
|