001: package com.mockrunner.mock.jdbc;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.ByteArrayOutputStream;
005: import java.io.InputStream;
006: import java.io.OutputStream;
007: import java.io.Reader;
008: import java.io.StringReader;
009: import java.io.StringWriter;
010: import java.io.Writer;
011: import java.sql.SQLException;
012: import java.sql.SQLXML;
013:
014: import javax.xml.parsers.DocumentBuilder;
015: import javax.xml.parsers.DocumentBuilderFactory;
016: import javax.xml.parsers.ParserConfigurationException;
017: import javax.xml.parsers.SAXParser;
018: import javax.xml.parsers.SAXParserFactory;
019: import javax.xml.stream.XMLInputFactory;
020: import javax.xml.stream.XMLOutputFactory;
021: import javax.xml.stream.XMLStreamException;
022: import javax.xml.stream.XMLStreamReader;
023: import javax.xml.stream.XMLStreamWriter;
024: import javax.xml.transform.Result;
025: import javax.xml.transform.Source;
026: import javax.xml.transform.dom.DOMResult;
027: import javax.xml.transform.dom.DOMSource;
028: import javax.xml.transform.sax.SAXResult;
029: import javax.xml.transform.sax.SAXSource;
030: import javax.xml.transform.stax.StAXResult;
031: import javax.xml.transform.stax.StAXSource;
032: import javax.xml.transform.stream.StreamResult;
033: import javax.xml.transform.stream.StreamSource;
034:
035: import org.jdom.Document;
036: import org.jdom.input.DOMBuilder;
037: import org.jdom.input.SAXBuilder;
038: import org.jdom.input.SAXHandler;
039: import org.jdom.output.DOMOutputter;
040: import org.jdom.output.Format;
041: import org.jdom.output.XMLOutputter;
042: import org.w3c.dom.Node;
043: import org.xml.sax.InputSource;
044:
045: import com.mockrunner.base.NestedApplicationException;
046: import com.mockrunner.util.common.StreamUtil;
047:
048: /**
049: * Mock implementation of <code>MockSQLXML</code>.
050: * Uses JDOM for XML handling.
051: */
052: public class MockSQLXML implements SQLXML, Cloneable {
053: private DocumentBuilder domParser;
054: private SAXParser saxParser;
055: private XMLOutputFactory outputFactory;
056: private XMLInputFactory inputFactory;
057: private SAXBuilder jdomParser;
058: private DOMBuilder jdomDOMBuilder;
059: private XMLOutputter xmlPrintOutputter;
060: private DOMOutputter domOutputter;
061: private XMLOutputter xmlCompareOutputter;
062: private Object content;
063: private boolean wasFreeCalled;
064: private boolean wasWriteMethodCalled;
065: private boolean wasReadMethodCalled;
066:
067: public MockSQLXML() {
068: createXMLObjects();
069: content = null;
070: wasFreeCalled = false;
071: wasWriteMethodCalled = false;
072: wasReadMethodCalled = false;
073: }
074:
075: public MockSQLXML(String stringContent) {
076: createXMLObjects();
077: content = stringContent;
078: wasFreeCalled = false;
079: wasWriteMethodCalled = false;
080: wasReadMethodCalled = false;
081: }
082:
083: public MockSQLXML(Reader readerContent) {
084: createXMLObjects();
085: content = StreamUtil.getReaderAsString(readerContent);
086: wasFreeCalled = false;
087: wasWriteMethodCalled = false;
088: wasReadMethodCalled = false;
089: }
090:
091: public MockSQLXML(InputStream inputStreamContent) {
092: createXMLObjects();
093: content = StreamUtil.getStreamAsByteArray(inputStreamContent);
094: wasFreeCalled = false;
095: wasWriteMethodCalled = false;
096: wasReadMethodCalled = false;
097: }
098:
099: public MockSQLXML(org.w3c.dom.Document documentContent) {
100: createXMLObjects();
101: content = documentContent;
102: wasFreeCalled = false;
103: wasWriteMethodCalled = false;
104: wasReadMethodCalled = false;
105: }
106:
107: protected DocumentBuilder createDocumentBuilder() {
108: try {
109: return DocumentBuilderFactory.newInstance()
110: .newDocumentBuilder();
111: } catch (ParserConfigurationException exc) {
112: throw new NestedApplicationException(exc);
113: }
114: }
115:
116: protected SAXParser createSAXParser() {
117: try {
118: return SAXParserFactory.newInstance().newSAXParser();
119: } catch (Exception exc) {
120: throw new NestedApplicationException(exc);
121: }
122: }
123:
124: protected XMLOutputFactory createXMLOutputFactory() {
125: return XMLOutputFactory.newInstance();
126: }
127:
128: protected XMLInputFactory createXMLInputFactory() {
129: return XMLInputFactory.newInstance();
130: }
131:
132: protected SAXBuilder createJDOMSAXBuilder() {
133: SAXBuilder builder = new SAXBuilder();
134: builder.setValidation(false);
135: return builder;
136: }
137:
138: protected DOMBuilder createJDOMDOMBuilder() {
139: return new DOMBuilder();
140: }
141:
142: protected XMLOutputter createJDOMXMLPrintOutputter() {
143: return new XMLOutputter(Format.getPrettyFormat());
144: }
145:
146: protected XMLOutputter createJDOMXMLCompareOutputter() {
147: Format format = Format.getCompactFormat();
148: format.setOmitDeclaration(true);
149: format.setOmitEncoding(true);
150: return new XMLOutputter(format);
151: }
152:
153: protected DOMOutputter createJDOMDOMOutputter() {
154: return new DOMOutputter();
155: }
156:
157: /**
158: * Returns the XML content as a string without affecting the state of
159: * the object. This method can be called multiple times unlike
160: * the <code>get</code> methods of <code>java.sql.SQLXML</code>.
161: * @return the XML content as a string
162: */
163: public String getContentAsString() {
164: try {
165: return contentToString();
166: } catch (Exception exc) {
167: throw new NestedApplicationException(exc);
168: }
169: }
170:
171: /**
172: * Returns the XML content as an <code>InputStream</code> without affecting the
173: * state of the object. This method can be called multiple times unlike
174: * the <code>get</code> methods of <code>java.sql.SQLXML</code>.
175: * @return the XML content as an <code>InputStream</code>
176: */
177: public InputStream getContentAsInputStream() throws SQLException {
178: try {
179: return contentToInputStream();
180: } catch (Exception exc) {
181: throw new NestedApplicationException(exc);
182: }
183: }
184:
185: /**
186: * Returns the XML content as a <code>Reader</code> without affecting the
187: * state of the object. This method can be called multiple times unlike
188: * the <code>get</code> methods of <code>java.sql.SQLXML</code>.
189: * @return the XML content as a <code>Reader</code>
190: */
191: public Reader getContentAsReader() throws SQLException {
192: try {
193: return contentToReader();
194: } catch (Exception exc) {
195: throw new NestedApplicationException(exc);
196: }
197: }
198:
199: /**
200: * Returns the XML content as a W3C <code>Document</code> without affecting
201: * the state of the object. This method can be called multiple times unlike
202: * the <code>get</code> methods of <code>java.sql.SQLXML</code>.
203: * @return the XML content as a W3C <code>Document</code>
204: */
205: public org.w3c.dom.Document getContentAsW3CDocument() {
206: try {
207: return contentToW3CDocument();
208: } catch (Exception exc) {
209: throw new NestedApplicationException(exc);
210: }
211: }
212:
213: public InputStream getBinaryStream() throws SQLException {
214: verifyRead();
215: wasReadMethodCalled = true;
216: try {
217: return contentToInputStream();
218: } catch (Exception exc) {
219: throw new SQLException(exc);
220: }
221: }
222:
223: public Reader getCharacterStream() throws SQLException {
224: verifyRead();
225: wasReadMethodCalled = true;
226: try {
227: return contentToReader();
228: } catch (Exception exc) {
229: throw new SQLException(exc);
230: }
231: }
232:
233: public Source getSource(Class sourceClass) throws SQLException {
234: verifyRead();
235: wasReadMethodCalled = true;
236: try {
237: if (null == sourceClass
238: || StreamSource.class.equals(sourceClass)) {
239: return new StreamSource(contentToInputStream());
240: }
241: if (DOMSource.class.equals(sourceClass)) {
242: return new DOMSource(contentToW3CDocument());
243: }
244: if (SAXSource.class.equals(sourceClass)) {
245: return new SAXSource(saxParser.getXMLReader(),
246: new InputSource(contentToInputStream()));
247: }
248: if (StAXSource.class.equals(sourceClass)) {
249: return new StAXSource(contentToXMLStreamReader());
250: }
251: } catch (Exception exc) {
252: throw new SQLException(exc);
253: }
254: throw new SQLException(sourceClass.getName()
255: + " not supported as Source");
256: }
257:
258: public String getString() throws SQLException {
259: verifyRead();
260: wasReadMethodCalled = true;
261: try {
262: return contentToString();
263: } catch (Exception exc) {
264: throw new SQLException(exc);
265: }
266: }
267:
268: public OutputStream setBinaryStream() throws SQLException {
269: verifyWrite();
270: wasWriteMethodCalled = true;
271: content = new ByteArrayOutputStream();
272: return (OutputStream) content;
273: }
274:
275: public Writer setCharacterStream() throws SQLException {
276: verifyWrite();
277: wasWriteMethodCalled = true;
278: content = new StringWriter();
279: return (Writer) content;
280: }
281:
282: public Result setResult(Class resultClass) throws SQLException {
283: verifyWrite();
284: wasWriteMethodCalled = true;
285: if (null == resultClass
286: || StreamResult.class.equals(resultClass)) {
287: content = new ByteArrayOutputStream();
288: return new StreamResult((OutputStream) content);
289: }
290: if (DOMResult.class.equals(resultClass)) {
291: org.w3c.dom.Document document = domParser.newDocument();
292: content = new DOMResult(document);
293: return (DOMResult) content;
294: }
295: if (SAXResult.class.equals(resultClass)) {
296: content = new SAXHandler();
297: return new SAXResult((SAXHandler) content);
298: }
299: if (StAXResult.class.equals(resultClass)) {
300: XMLStreamWriter xmlWriter;
301: ByteArrayOutputStream outStream = new ByteArrayOutputStream();
302: try {
303: xmlWriter = outputFactory
304: .createXMLStreamWriter(outStream);
305: } catch (XMLStreamException exc) {
306: throw new SQLException(exc);
307: }
308: content = new StreamWriterOutputStreamMapping(xmlWriter,
309: outStream);
310: return new StAXResult(xmlWriter);
311: }
312: throw new SQLException(resultClass.getName()
313: + " not supported as Result");
314: }
315:
316: public void setString(String value) throws SQLException {
317: verifyWrite();
318: wasWriteMethodCalled = true;
319: content = value;
320: }
321:
322: public void free() throws SQLException {
323: wasFreeCalled = true;
324: }
325:
326: /**
327: * Returns if {@link #free} has been called.
328: * @return <code>true</code> if {@link #free} has been called,
329: * <code>false</code> otherwise
330: */
331: public boolean wasFreeCalled() {
332: return wasFreeCalled;
333: }
334:
335: /**
336: * Returns if this object is readable.
337: * @return <code>true</code> this object is readable,
338: * <code>false</code> otherwise
339: */
340: public boolean isReadable() {
341: return !(wasFreeCalled || wasReadMethodCalled);
342: }
343:
344: /**
345: * Returns if this object is writeable.
346: * @return <code>true</code> this object is writeable,
347: * <code>false</code> otherwise
348: */
349: public boolean isWriteable() {
350: return !(wasFreeCalled || wasWriteMethodCalled);
351: }
352:
353: public boolean equals(Object otherObject) {
354: if (null == otherObject)
355: return false;
356: if (this == otherObject)
357: return true;
358: if (!otherObject.getClass().equals(this .getClass()))
359: return false;
360: MockSQLXML otherSQLXML = (MockSQLXML) otherObject;
361: if (wasFreeCalled != otherSQLXML.wasFreeCalled())
362: return false;
363: if (null == content && null == otherSQLXML.content)
364: return true;
365: if (null == content || null == otherSQLXML.content)
366: return false;
367: try {
368: Document this Content = contentToJDOMDocument();
369: Document otherContent = otherSQLXML.contentToJDOMDocument();
370: if (null == this Content || null == otherContent)
371: return false;
372: String this ContentAsString = xmlCompareOutputter
373: .outputString(this Content);
374: String otherContentAsString = xmlCompareOutputter
375: .outputString(otherContent);
376: return this ContentAsString.equals(otherContentAsString);
377: } catch (Exception exc) {
378: return false;
379: }
380: }
381:
382: public int hashCode() {
383: int hashCode = 17;
384: if (null != content) {
385: try {
386: Document document = contentToJDOMDocument();
387: if (null == document)
388: return hashCode;
389: String documentAsString = xmlCompareOutputter
390: .outputString(document);
391: if (null != documentAsString)
392: hashCode = (31 * hashCode)
393: + documentAsString.hashCode();
394: } catch (Exception exc) {
395:
396: }
397: }
398: hashCode = (31 * hashCode) + (wasFreeCalled ? 31 : 62);
399: return hashCode;
400: }
401:
402: public Object clone() {
403: try {
404: MockSQLXML other = (MockSQLXML) super .clone();
405: other.domParser = createDocumentBuilder();
406: other.saxParser = createSAXParser();
407: other.outputFactory = createXMLOutputFactory();
408: other.inputFactory = createXMLInputFactory();
409: other.jdomParser = createJDOMSAXBuilder();
410: other.jdomDOMBuilder = createJDOMDOMBuilder();
411: other.xmlPrintOutputter = createJDOMXMLPrintOutputter();
412: other.domOutputter = createJDOMDOMOutputter();
413: other.xmlCompareOutputter = createJDOMXMLCompareOutputter();
414: if (null != content) {
415: try {
416: Document document = contentToJDOMDocument();
417: other.content = document.clone();
418: } catch (Exception exc) {
419: other.content = null;
420: }
421: }
422: return other;
423: } catch (CloneNotSupportedException exc) {
424: throw new NestedApplicationException(exc);
425: }
426: }
427:
428: public String toString() {
429: StringBuffer buffer = new StringBuffer("XML data:\n");
430: if (null == content) {
431: buffer.append("null");
432: } else {
433: try {
434: Document document = contentToJDOMDocument();
435: if (null != document)
436: buffer.append(document.toString());
437: } catch (Exception exc) {
438: buffer.append(exc.getMessage());
439: }
440: }
441: return buffer.toString();
442: }
443:
444: private void createXMLObjects() {
445: domParser = createDocumentBuilder();
446: saxParser = createSAXParser();
447: outputFactory = createXMLOutputFactory();
448: inputFactory = createXMLInputFactory();
449: jdomParser = createJDOMSAXBuilder();
450: jdomDOMBuilder = createJDOMDOMBuilder();
451: xmlPrintOutputter = createJDOMXMLPrintOutputter();
452: domOutputter = createJDOMDOMOutputter();
453: xmlCompareOutputter = createJDOMXMLCompareOutputter();
454: }
455:
456: private void verifyWrite() throws SQLException {
457: if (!isWriteable()) {
458: throw new SQLException("not writeable");
459: }
460: }
461:
462: private void verifyRead() throws SQLException {
463: if (!isReadable()) {
464: throw new SQLException("not readable");
465: }
466: if (null == content) {
467: throw new SQLException("no content");
468: }
469: }
470:
471: private Document contentToJDOMDocument() throws Exception {
472: Document jdomDocument = null;
473: if (content instanceof Document) {
474: jdomDocument = (Document) content;
475: } else if (content instanceof String) {
476: jdomDocument = jdomParser.build(new StringReader(
477: (String) content));
478: } else if (content instanceof StringWriter) {
479: jdomDocument = jdomParser.build(new StringReader(
480: ((StringWriter) content).toString()));
481: } else if (content instanceof ByteArrayOutputStream) {
482: jdomDocument = jdomParser.build(new ByteArrayInputStream(
483: ((ByteArrayOutputStream) content).toByteArray()));
484: } else if (content instanceof byte[]) {
485: jdomDocument = jdomParser.build(new ByteArrayInputStream(
486: (byte[]) content));
487: } else if (content instanceof org.w3c.dom.Document) {
488: jdomDocument = jdomDOMBuilder
489: .build((org.w3c.dom.Document) content);
490: } else if (content instanceof DOMResult) {
491: Node node = ((DOMResult) content).getNode();
492: org.w3c.dom.Document document = null;
493: if (node instanceof org.w3c.dom.Document) {
494: document = (org.w3c.dom.Document) node;
495: } else {
496: document = domParser.newDocument();
497: document.appendChild(document.importNode(node, true));
498: }
499: jdomDocument = jdomDOMBuilder.build(document);
500: } else if (content instanceof SAXHandler) {
501: jdomDocument = ((SAXHandler) content).getDocument();
502: } else if (content instanceof StreamWriterOutputStreamMapping) {
503: XMLStreamWriter xmlWriter = ((StreamWriterOutputStreamMapping) content)
504: .getStreamWriter();
505: xmlWriter.flush();
506: xmlWriter.close();
507: ByteArrayOutputStream outStream = ((StreamWriterOutputStreamMapping) content)
508: .getOutputStream();
509: jdomDocument = jdomParser.build(new ByteArrayInputStream(
510: outStream.toByteArray()));
511: }
512: return jdomDocument;
513: }
514:
515: private String contentToString() throws Exception {
516: Document jdomDocument = contentToJDOMDocument();
517: if (null != jdomDocument) {
518: return xmlPrintOutputter.outputString(jdomDocument);
519: }
520: return null;
521: }
522:
523: private Reader contentToReader() throws Exception {
524: Document jdomDocument = contentToJDOMDocument();
525: if (null != jdomDocument) {
526: return new StringReader(xmlPrintOutputter
527: .outputString(jdomDocument));
528: }
529: return null;
530: }
531:
532: private InputStream contentToInputStream() throws Exception {
533: Document jdomDocument = contentToJDOMDocument();
534: if (null != jdomDocument) {
535: ByteArrayOutputStream outStream = new ByteArrayOutputStream();
536: xmlPrintOutputter.output(jdomDocument, outStream);
537: outStream.flush();
538: return new ByteArrayInputStream(outStream.toByteArray());
539: }
540: return null;
541: }
542:
543: private org.w3c.dom.Document contentToW3CDocument()
544: throws Exception {
545: Document jdomDocument = contentToJDOMDocument();
546: if (null != jdomDocument) {
547: return domOutputter.output(jdomDocument);
548: }
549: return null;
550: }
551:
552: private XMLStreamReader contentToXMLStreamReader() throws Exception {
553: Document jdomDocument = contentToJDOMDocument();
554: if (null != jdomDocument) {
555: ByteArrayOutputStream outStream = new ByteArrayOutputStream();
556: xmlPrintOutputter.output(jdomDocument, outStream);
557: outStream.flush();
558: InputStream inStream = new ByteArrayInputStream(outStream
559: .toByteArray());
560: return inputFactory.createXMLStreamReader(inStream);
561: }
562: return null;
563: }
564:
565: private class StreamWriterOutputStreamMapping {
566: private XMLStreamWriter streamWriter;
567: private ByteArrayOutputStream outputStream;
568:
569: public StreamWriterOutputStreamMapping(
570: XMLStreamWriter streamWriter,
571: ByteArrayOutputStream outputStream) {
572: this .streamWriter = streamWriter;
573: this .outputStream = outputStream;
574: }
575:
576: public XMLStreamWriter getStreamWriter() {
577: return streamWriter;
578: }
579:
580: public ByteArrayOutputStream getOutputStream() {
581: return outputStream;
582: }
583: }
584: }
|