001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Emil Ong
028: */
029:
030: package com.caucho.xml.saaj;
031:
032: import java.io.*;
033: import java.util.*;
034: import javax.activation.*;
035:
036: import javax.xml.XMLConstants;
037: import javax.xml.soap.*;
038:
039: import org.w3c.dom.*;
040: import org.xml.sax.*;
041:
042: import com.caucho.util.Base64;
043: import com.caucho.xml.Xml;
044: import com.caucho.xml.XmlPrinter;
045:
046: public class SOAPMessageImpl extends SOAPMessage {
047: private static final Name SOAP_NAMESPACE_NAME = new NameImpl(
048: XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
049: SOAPConstants.SOAP_ENV_PREFIX, XMLConstants.XMLNS_ATTRIBUTE);
050:
051: private final ArrayList<AttachmentPart> _attachments = new ArrayList<AttachmentPart>();
052:
053: private final HashMap<String, Object> _properties = new HashMap<String, Object>();
054:
055: private static Random _r = new Random();
056:
057: private String _description;
058: private SOAPPart _part;
059: private SOAPFactory _factory;
060: private String _protocol;
061: private boolean _saveRequired = true;
062: private MimeHeaders _headers = new MimeHeaders();
063:
064: public static void setRandomSeed(long seed) {
065: _r = new Random(seed);
066: }
067:
068: SOAPMessageImpl(SOAPFactory factory, String protocol)
069: throws SOAPException {
070: init(factory, protocol);
071: _part = new SOAPPartImpl(factory, protocol);
072: }
073:
074: SOAPMessageImpl(SOAPFactory factory, String protocol,
075: MimeHeaders headers, InputStream in) throws IOException,
076: SOAPException {
077: init(factory, protocol);
078:
079: try {
080: Document doc = new Xml().parseDocument(in);
081: _part = new SOAPPartImpl(factory, protocol, doc);
082: } catch (SAXException e) {
083: throw new SOAPException(e);
084: }
085:
086: // XXX: the RI ignores the headers argument passed into
087: // MessageFactory.createMessage(), so we will too for now.
088: }
089:
090: private void init(SOAPFactory factory, String protocol) {
091: _factory = factory;
092: _protocol = protocol;
093: _properties.put(WRITE_XML_DECLARATION, "false");
094: _properties.put(CHARACTER_SET_ENCODING, "utf-8");
095: _headers.addHeader("Content-Type", "text/xml");
096: }
097:
098: public void addAttachmentPart(AttachmentPart attachmentPart) {
099: _attachments.add(attachmentPart);
100: }
101:
102: public int countAttachments() {
103: return _attachments.size();
104: }
105:
106: public AttachmentPart createAttachmentPart() {
107: return new AttachmentPartImpl();
108: }
109:
110: public AttachmentPart createAttachmentPart(DataHandler dataHandler) {
111: AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
112: attachmentPart.setDataHandler(dataHandler);
113:
114: return attachmentPart;
115: }
116:
117: public AttachmentPart createAttachmentPart(Object content,
118: String contentType) {
119: AttachmentPartImpl attachmentPart = new AttachmentPartImpl();
120: attachmentPart.setContent(content, contentType);
121:
122: return attachmentPart;
123: }
124:
125: public AttachmentPart getAttachment(SOAPElement element)
126: throws SOAPException {
127: String href = element.getAttribute("href");
128:
129: if (href != null && !"".equals(href)) {
130: // XXX other prefixes for contentId?
131: if (href.startsWith("cid:")) {
132: String contentId = '<' + href
133: .substring("cid:".length()) + '>';
134: return findAttachmentByContentId(contentId);
135: } else
136: return findAttachmentByContentLocation(href);
137: }
138:
139: href = element.getValue();
140:
141: if (href != null && !"".equals(href)) {
142: if (href.startsWith("cid:")) {
143: String contentId = '<' + href
144: .substring("cid:".length()) + '>';
145: return findAttachmentByContentId(contentId);
146: } else
147: return findAttachmentByContentLocation(href);
148: }
149:
150: return null;
151: }
152:
153: private AttachmentPart findAttachmentByContentId(String contentId) {
154: for (int i = 0; i < _attachments.size(); i++) {
155: if (contentId.equals(_attachments.get(i).getContentId()))
156: return _attachments.get(i);
157: }
158:
159: return null;
160: }
161:
162: private AttachmentPart findAttachmentByContentLocation(
163: String contentLocation) {
164: for (int i = 0; i < _attachments.size(); i++) {
165: if (contentLocation.equals(_attachments.get(i)
166: .getContentLocation()))
167: return _attachments.get(i);
168: }
169:
170: return null;
171: }
172:
173: public Iterator getAttachments() {
174: return _attachments.iterator();
175: }
176:
177: public Iterator getAttachments(MimeHeaders headers) {
178: return new MatchingHeadersIterator(headers);
179: }
180:
181: public String getContentDescription() {
182: return _description;
183: }
184:
185: public void setContentDescription(String description) {
186: _description = description;
187: }
188:
189: public MimeHeaders getMimeHeaders() {
190: return _headers;
191: }
192:
193: public Object getProperty(String property) throws SOAPException {
194: Object o = _properties.get(property);
195:
196: if (o == null)
197: throw new SOAPException("Unrecognized property : "
198: + property);
199:
200: return o;
201: }
202:
203: public SOAPBody getSOAPBody() throws SOAPException {
204: return _part.getEnvelope().getBody();
205: }
206:
207: public SOAPHeader getSOAPHeader() throws SOAPException {
208: return _part.getEnvelope().getHeader();
209: }
210:
211: public SOAPPart getSOAPPart() {
212: return _part;
213: }
214:
215: public void removeAllAttachments() {
216: _attachments.clear();
217: }
218:
219: public void removeAttachments(MimeHeaders headers) {
220: Iterator iterator = getAttachments(headers);
221:
222: while (iterator.hasNext()) {
223: iterator.next();
224: iterator.remove();
225: }
226: }
227:
228: public void saveChanges() throws SOAPException {
229: // XXX???
230:
231: _saveRequired = false; // weird logic required by TCK
232: }
233:
234: public boolean saveRequired() {
235: return _saveRequired;
236: }
237:
238: public void setProperty(String property, Object value)
239: throws SOAPException {
240: /* API says this is necessary, but TCK disagrees:
241:
242: if (! property.equals(WRITE_XML_DECLARATION) &&
243: ! property.equals(CHARACTER_SET_ENCODING))
244: throw new SOAPException("Unrecognized property : " + property);
245: */
246:
247: _properties.put(property, value);
248: }
249:
250: public void writeTo(OutputStream out) throws SOAPException,
251: IOException {
252: // As specified by API
253: saveChanges();
254:
255: OutputStreamWriter osw = new OutputStreamWriter(out);
256: PrintWriter w = new PrintWriter(osw);
257:
258: String separator = null;
259:
260: if (_attachments.size() > 0) {
261: separator = "------=_Part_" + _r.nextLong();
262: w.println(separator);
263:
264: Iterator iterator = getMimeHeaders().getAllHeaders();
265:
266: while (iterator.hasNext()) {
267: MimeHeader header = (MimeHeader) iterator.next();
268: w.println(header.getName() + ": " + header.getValue());
269: }
270:
271: w.println();
272: }
273:
274: XmlPrinter printer = new XmlPrinter(w);
275: printer.setEncoding((String) _properties
276: .get(CHARACTER_SET_ENCODING));
277:
278: boolean printDeclaration = Boolean.valueOf((String) _properties
279: .get(WRITE_XML_DECLARATION));
280:
281: printer.setPrintDeclaration(printDeclaration);
282:
283: // ensure that the soap envelope prefix is defined when we do output
284: SOAPEnvelope envelope = _part.getEnvelope();
285:
286: Iterator attrs = envelope.getAllAttributes();
287: boolean foundSoapNS = false;
288:
289: while (attrs.hasNext()) {
290: Name name = (Name) attrs.next();
291: String value = envelope.getAttributeValue(name);
292:
293: if (value.equals(envelope.getNamespaceURI())
294: && "xmlns".equals(name.getPrefix())) {
295: foundSoapNS = true;
296: break;
297: }
298: }
299:
300: if (!foundSoapNS)
301: envelope.addAttribute(SOAP_NAMESPACE_NAME, envelope
302: .getNamespaceURI());
303:
304: printer.printNode(_part);
305:
306: if (!foundSoapNS)
307: envelope.removeAttribute(SOAP_NAMESPACE_NAME);
308:
309: // write the attachments
310:
311: if (_attachments.size() > 0)
312: w.println();
313:
314: for (int i = 0; i < _attachments.size(); i++) {
315: w.println(separator);
316:
317: AttachmentPart ap = _attachments.get(i);
318:
319: Iterator iterator = ap.getAllMimeHeaders();
320:
321: while (iterator.hasNext()) {
322: MimeHeader header = (MimeHeader) iterator.next();
323: w.println(header.getName() + ": " + header.getValue());
324: }
325:
326: w.println();
327:
328: Base64.encode(w, ap.getRawContent());
329: }
330:
331: if (_attachments.size() > 0) {
332: w.println();
333: w.println(separator + "--");
334: }
335:
336: w.flush();
337: }
338:
339: // org.w3c.dom.Document
340:
341: public org.w3c.dom.Node adoptNode(org.w3c.dom.Node source) {
342: throw new UnsupportedOperationException();
343: }
344:
345: public Attr createAttribute(String name) {
346: throw new UnsupportedOperationException();
347: }
348:
349: public Attr createAttributeNS(String namespaceURI,
350: String qualifiedName) {
351: throw new UnsupportedOperationException();
352: }
353:
354: public CDATASection createCDATASection(String data) {
355: throw new UnsupportedOperationException();
356: }
357:
358: public Comment createComment(String data) {
359: throw new UnsupportedOperationException();
360: }
361:
362: public DocumentFragment createDocumentFragment() {
363: throw new UnsupportedOperationException();
364: }
365:
366: public Element createElement(String tagName) {
367: throw new UnsupportedOperationException();
368: }
369:
370: public Element createElementNS(String namespaceURI,
371: String qualifiedName) {
372: throw new UnsupportedOperationException();
373: }
374:
375: public EntityReference createEntityReference(String name) {
376: throw new UnsupportedOperationException();
377: }
378:
379: public ProcessingInstruction createProcessingInstruction(
380: String target, String data) {
381: throw new UnsupportedOperationException();
382: }
383:
384: public org.w3c.dom.Text createTextNode(String data) {
385: throw new UnsupportedOperationException();
386: }
387:
388: public DocumentType getDoctype() {
389: throw new UnsupportedOperationException();
390: }
391:
392: public Element getDocumentElement() {
393: throw new UnsupportedOperationException();
394: }
395:
396: public String getDocumentURI() {
397: throw new UnsupportedOperationException();
398: }
399:
400: public DOMConfiguration getDomConfig() {
401: throw new UnsupportedOperationException();
402: }
403:
404: public Element getElementById(String elementId) {
405: throw new UnsupportedOperationException();
406: }
407:
408: public NodeList getElementsByTagName(String tagname) {
409: throw new UnsupportedOperationException();
410: }
411:
412: public NodeList getElementsByTagNameNS(String namespaceURI,
413: String localName) {
414: throw new UnsupportedOperationException();
415: }
416:
417: public DOMImplementation getImplementation() {
418: throw new UnsupportedOperationException();
419: }
420:
421: public String getInputEncoding() {
422: throw new UnsupportedOperationException();
423: }
424:
425: public boolean getStrictErrorChecking() {
426: throw new UnsupportedOperationException();
427: }
428:
429: public String getXmlEncoding() {
430: throw new UnsupportedOperationException();
431: }
432:
433: public boolean getXmlStandalone() {
434: throw new UnsupportedOperationException();
435: }
436:
437: public String getXmlVersion() {
438: throw new UnsupportedOperationException();
439: }
440:
441: public org.w3c.dom.Node importNode(org.w3c.dom.Node importedNode,
442: boolean deep) {
443: throw new UnsupportedOperationException();
444: }
445:
446: public void normalizeDocument() {
447: throw new UnsupportedOperationException();
448: }
449:
450: public org.w3c.dom.Node renameNode(org.w3c.dom.Node n,
451: String namespaceURI, String qualifiedName)
452: throws DOMException {
453: throw new UnsupportedOperationException();
454: }
455:
456: public void setDocumentURI(String documentURI) {
457: throw new UnsupportedOperationException();
458: }
459:
460: public void setStrictErrorChecking(boolean strictErrorChecking) {
461: throw new UnsupportedOperationException();
462: }
463:
464: public void setXmlStandalone(boolean xmlStandalone) {
465: throw new UnsupportedOperationException();
466: }
467:
468: public void setXmlVersion(String xmlVersion) {
469: throw new UnsupportedOperationException();
470: }
471:
472: // org.w3c.dom.Node
473:
474: public org.w3c.dom.Node appendChild(org.w3c.dom.Node newChild) {
475: throw new UnsupportedOperationException();
476: }
477:
478: public org.w3c.dom.Node cloneNode(boolean deep) {
479: throw new UnsupportedOperationException();
480: }
481:
482: public short compareDocumentPosition(org.w3c.dom.Node other) {
483: throw new UnsupportedOperationException();
484: }
485:
486: public NamedNodeMap getAttributes() {
487: throw new UnsupportedOperationException();
488: }
489:
490: public String getBaseURI() {
491: throw new UnsupportedOperationException();
492: }
493:
494: public NodeList getChildNodes() {
495: throw new UnsupportedOperationException();
496: }
497:
498: public Object getFeature(String feature, String version) {
499: throw new UnsupportedOperationException();
500: }
501:
502: public org.w3c.dom.Node getFirstChild() {
503: throw new UnsupportedOperationException();
504: }
505:
506: public org.w3c.dom.Node getLastChild() {
507: throw new UnsupportedOperationException();
508: }
509:
510: public String getLocalName() {
511: throw new UnsupportedOperationException();
512: }
513:
514: public String getNamespaceURI() {
515: throw new UnsupportedOperationException();
516: }
517:
518: public org.w3c.dom.Node getNextSibling() {
519: throw new UnsupportedOperationException();
520: }
521:
522: public String getNodeName() {
523: throw new UnsupportedOperationException();
524: }
525:
526: public short getNodeType() {
527: throw new UnsupportedOperationException();
528: }
529:
530: public String getNodeValue() {
531: throw new UnsupportedOperationException();
532: }
533:
534: public Document getOwnerDocument() {
535: throw new UnsupportedOperationException();
536: }
537:
538: public org.w3c.dom.Node getParentNode() {
539: throw new UnsupportedOperationException();
540: }
541:
542: public String getPrefix() {
543: throw new UnsupportedOperationException();
544: }
545:
546: public org.w3c.dom.Node getPreviousSibling() {
547: throw new UnsupportedOperationException();
548: }
549:
550: public String getTextContent() {
551: throw new UnsupportedOperationException();
552: }
553:
554: public Object getUserData(String key) {
555: throw new UnsupportedOperationException();
556: }
557:
558: public boolean hasAttributes() {
559: throw new UnsupportedOperationException();
560: }
561:
562: public boolean hasChildNodes() {
563: throw new UnsupportedOperationException();
564: }
565:
566: public org.w3c.dom.Node insertBefore(org.w3c.dom.Node newChild,
567: org.w3c.dom.Node refChild) {
568: throw new UnsupportedOperationException();
569: }
570:
571: public boolean isDefaultNamespace(String namespaceURI) {
572: throw new UnsupportedOperationException();
573: }
574:
575: public boolean isEqualNode(org.w3c.dom.Node arg) {
576: throw new UnsupportedOperationException();
577: }
578:
579: public boolean isSameNode(org.w3c.dom.Node other) {
580: throw new UnsupportedOperationException();
581: }
582:
583: public boolean isSupported(String feature, String version) {
584: throw new UnsupportedOperationException();
585: }
586:
587: public String lookupNamespaceURI(String prefix) {
588: throw new UnsupportedOperationException();
589: }
590:
591: public String lookupPrefix(String namespaceURI) {
592: throw new UnsupportedOperationException();
593: }
594:
595: public void normalize() {
596: throw new UnsupportedOperationException();
597: }
598:
599: public org.w3c.dom.Node removeChild(org.w3c.dom.Node oldChild) {
600: throw new UnsupportedOperationException();
601: }
602:
603: public org.w3c.dom.Node replaceChild(org.w3c.dom.Node newChild,
604: org.w3c.dom.Node oldChild) {
605: throw new UnsupportedOperationException();
606: }
607:
608: public void setNodeValue(String nodeValue) {
609: throw new UnsupportedOperationException();
610: }
611:
612: public void setPrefix(String prefix) {
613: throw new UnsupportedOperationException();
614: }
615:
616: public void setTextContent(String textContent) {
617: throw new UnsupportedOperationException();
618: }
619:
620: public Object setUserData(String key, Object data,
621: UserDataHandler handler) {
622: throw new UnsupportedOperationException();
623: }
624:
625: private class MatchingHeadersIterator implements Iterator {
626: private MimeHeaders _headers;
627: private int _current = -1;
628: private int _last = -1;
629:
630: public MatchingHeadersIterator(MimeHeaders headers) {
631: _headers = headers;
632:
633: advance();
634: }
635:
636: public Object next() {
637: if (hasNext()) {
638: Object next = _attachments.get(_current);
639:
640: advance();
641:
642: return next;
643: }
644:
645: throw new NoSuchElementException();
646: }
647:
648: public boolean hasNext() {
649: return _current < _attachments.size();
650: }
651:
652: public void remove() {
653: _attachments.remove(_last);
654: }
655:
656: private void advance() {
657: _last = _current;
658:
659: for (_current++; _current < _attachments.size(); _current++) {
660: if (attachmentMatchesHeaders(_attachments.get(_current)))
661: break;
662: }
663: }
664:
665: private boolean attachmentMatchesHeaders(
666: AttachmentPart attachment) {
667: Iterator iterator = _headers.getAllHeaders();
668:
669: while (iterator.hasNext()) {
670: MimeHeader header = (MimeHeader) iterator.next();
671: String[] values = attachment.getMimeHeader(header
672: .getName());
673:
674: boolean headerFound = false;
675:
676: for (String value : values) {
677: if (header.getValue().equals(value)) {
678: headerFound = true;
679: break;
680: }
681: }
682:
683: if (!headerFound)
684: return false;
685: }
686:
687: return true;
688: }
689: }
690: }
|