1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.ws.message.saaj; 27 28 import com.sun.istack.internal.FragmentContentHandler; 29 import com.sun.istack.internal.NotNull; 30 import com.sun.istack.internal.Nullable; 31 import com.sun.istack.internal.XMLStreamException2; 32 import com.sun.xml.internal.bind.api.Bridge; 33 import com.sun.xml.internal.bind.unmarshaller.DOMScanner; 34 import com.sun.xml.internal.ws.api.SOAPVersion; 35 import com.sun.xml.internal.ws.api.message.*; 36 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl; 37 import com.sun.xml.internal.ws.spi.db.XMLBridge; 38 import com.sun.xml.internal.ws.streaming.DOMStreamReader; 39 import com.sun.xml.internal.ws.util.ASCIIUtility; 40 import com.sun.xml.internal.ws.util.DOMUtil; 41 import org.w3c.dom.Attr; 42 import org.w3c.dom.Element; 43 import org.w3c.dom.NamedNodeMap; 44 import org.w3c.dom.Node; 45 import org.xml.sax.ContentHandler; 46 import org.xml.sax.ErrorHandler; 47 import org.xml.sax.SAXException; 48 import org.xml.sax.helpers.AttributesImpl; 49 import org.xml.sax.helpers.LocatorImpl; 50 51 import javax.activation.DataHandler; 52 import javax.xml.bind.JAXBException; 53 import javax.xml.bind.Unmarshaller; 54 import javax.xml.soap.*; 55 import javax.xml.stream.XMLStreamException; 56 import javax.xml.stream.XMLStreamReader; 57 import javax.xml.stream.XMLStreamWriter; 58 import javax.xml.transform.Source; 59 import javax.xml.transform.dom.DOMSource; 60 import javax.xml.transform.stream.StreamSource; 61 import javax.xml.ws.WebServiceException; 62 import java.io.IOException; 63 import java.io.InputStream; 64 import java.io.OutputStream; 65 import java.util.HashMap; 66 import java.util.Iterator; 67 import java.util.List; 68 import java.util.Map; 69 70 /** 71 * {@link Message} implementation backed by {@link SOAPMessage}. 72 * 73 * @author Vivek Pandey 74 * @author Rama Pulavarthi 75 */ 76 public class SAAJMessage extends Message { 77 // flag to switch between representations 78 private boolean parsedMessage; 79 // flag to check if Message API is exercised; 80 private boolean accessedMessage; 81 private final SOAPMessage sm; 82 83 private MessageHeaders headers; 84 private List<Element> bodyParts; 85 private Element payload; 86 87 private String payloadLocalName; 88 private String payloadNamespace; 89 private SOAPVersion soapVersion; 90 91 //Collect the attrbutes on the enclosing elements so that the same message can be reproduced without loss of any 92 // valuable info 93 private NamedNodeMap bodyAttrs, headerAttrs, envelopeAttrs; 94 95 public SAAJMessage(SOAPMessage sm) { 96 this.sm = sm; 97 } 98 99 /** 100 * This constructor is a convenience and called by the {@link #copy} 101 * 102 * @param headers 103 * @param sm 104 */ 105 private SAAJMessage(MessageHeaders headers, AttachmentSet as, SOAPMessage sm, SOAPVersion version) { 106 this.sm = sm; 107 this.parse(); 108 if(headers == null) 109 headers = new HeaderList(version); 110 this.headers = headers; 111 this.attachmentSet = as; 112 } 113 114 private void parse() { 115 if (!parsedMessage) { 116 try { 117 access(); 118 if (headers == null) 119 headers = new HeaderList(getSOAPVersion()); 120 SOAPHeader header = sm.getSOAPHeader(); 121 if (header != null) { 122 headerAttrs = header.getAttributes(); 123 Iterator iter = header.examineAllHeaderElements(); 124 while (iter.hasNext()) { 125 headers.add(new SAAJHeader((SOAPHeaderElement) iter.next())); 126 } 127 } 128 attachmentSet = new SAAJAttachmentSet(sm); 129 130 parsedMessage = true; 131 } catch (SOAPException e) { 132 throw new WebServiceException(e); 133 } 134 } 135 } 136 137 protected void access() { 138 if (!accessedMessage) { 139 try { 140 envelopeAttrs = sm.getSOAPPart().getEnvelope().getAttributes(); 141 Node body = sm.getSOAPBody(); 142 bodyAttrs = body.getAttributes(); 143 soapVersion = SOAPVersion.fromNsUri(body.getNamespaceURI()); 144 //cature all the body elements 145 bodyParts = DOMUtil.getChildElements(body); 146 //we treat payload as the first body part 147 payload = bodyParts.size() > 0 ? bodyParts.get(0) : null; 148 // hope this is correct. Caching the localname and namespace of the payload should be fine 149 // but what about if a Handler replaces the payload with something else? Weel, may be it 150 // will be error condition anyway 151 if (payload != null) { 152 payloadLocalName = payload.getLocalName(); 153 payloadNamespace = payload.getNamespaceURI(); 154 } 155 accessedMessage = true; 156 } catch (SOAPException e) { 157 throw new WebServiceException(e); 158 } 159 } 160 } 161 162 public boolean hasHeaders() { 163 parse(); 164 return headers.hasHeaders(); 165 } 166 167 public @NotNull MessageHeaders getHeaders() { 168 parse(); 169 return headers; 170 } 171 172 /** 173 * Gets the attachments of this message 174 * (attachments live outside a message.) 175 */ 176 @Override 177 public @NotNull AttachmentSet getAttachments() { 178 if (attachmentSet == null) attachmentSet = new SAAJAttachmentSet(sm); 179 return attachmentSet; 180 } 181 182 /** 183 * Optimization hint for the derived class to check 184 * if we may have some attachments. 185 */ 186 @Override 187 protected boolean hasAttachments() { 188 return !getAttachments().isEmpty(); 189 } 190 191 public @Nullable String getPayloadLocalPart() { 192 soapBodyFirstChild(); 193 return payloadLocalName; 194 } 195 196 public String getPayloadNamespaceURI() { 197 soapBodyFirstChild(); 198 return payloadNamespace; 199 } 200 201 public boolean hasPayload() { 202 return soapBodyFirstChild() != null; 203 } 204 205 private void addAttributes(Element e, NamedNodeMap attrs) { 206 if(attrs == null) 207 return; 208 String elPrefix = e.getPrefix(); 209 for(int i=0; i < attrs.getLength();i++) { 210 Attr a = (Attr)attrs.item(i); 211 //check if attr is ns declaration 212 if("xmlns".equals(a.getPrefix()) || "xmlns".equals(a.getLocalName())) { 213 if(elPrefix == null && a.getLocalName().equals("xmlns")) { 214 // the target element has already default ns declaration, dont' override it 215 continue; 216 } else if(elPrefix != null && "xmlns".equals(a.getPrefix()) && elPrefix.equals(a.getLocalName())) { 217 //dont bind the prefix to ns again, its already in the target element. 218 continue; 219 } 220 e.setAttributeNS(a.getNamespaceURI(),a.getName(),a.getValue()); 221 continue; 222 } 223 e.setAttributeNS(a.getNamespaceURI(),a.getName(),a.getValue()); 224 } 225 } 226 227 public Source readEnvelopeAsSource() { 228 try { 229 if (!parsedMessage) { 230 SOAPEnvelope se = sm.getSOAPPart().getEnvelope(); 231 return new DOMSource(se); 232 233 } else { 234 SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); 235 addAttributes(msg.getSOAPPart().getEnvelope(),envelopeAttrs); 236 237 SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); 238 addAttributes(newBody, bodyAttrs); 239 for (Element part : bodyParts) { 240 Node n = newBody.getOwnerDocument().importNode(part, true); 241 newBody.appendChild(n); 242 } 243 addAttributes(msg.getSOAPHeader(),headerAttrs); 244 for (Header header : headers.asList()) { 245 header.writeTo(msg); 246 } 247 SOAPEnvelope se = msg.getSOAPPart().getEnvelope(); 248 return new DOMSource(se); 249 } 250 } catch (SOAPException e) { 251 throw new WebServiceException(e); 252 } 253 } 254 255 public SOAPMessage readAsSOAPMessage() throws SOAPException { 256 if (!parsedMessage) { 257 return sm; 258 } else { 259 SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); 260 addAttributes(msg.getSOAPPart().getEnvelope(),envelopeAttrs); 261 SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); 262 addAttributes(newBody, bodyAttrs); 263 for (Element part : bodyParts) { 264 Node n = newBody.getOwnerDocument().importNode(part, true); 265 newBody.appendChild(n); 266 } 267 addAttributes(msg.getSOAPHeader(),headerAttrs); 268 for (Header header : headers.asList()) { 269 header.writeTo(msg); 270 } 271 for (Attachment att : getAttachments()) { 272 AttachmentPart part = msg.createAttachmentPart(); 273 part.setDataHandler(att.asDataHandler()); 274 part.setContentId('<' + att.getContentId() + '>'); 275 addCustomMimeHeaders(att, part); 276 msg.addAttachmentPart(part); 277 } 278 msg.saveChanges(); 279 return msg; 280 } 281 } 282 283 private void addCustomMimeHeaders(Attachment att, AttachmentPart part) { 284 if (att instanceof AttachmentEx) { 285 Iterator<AttachmentEx.MimeHeader> allMimeHeaders = ((AttachmentEx) att).getMimeHeaders(); 286 while (allMimeHeaders.hasNext()) { 287 AttachmentEx.MimeHeader mh = allMimeHeaders.next(); 288 String name = mh.getName(); 289 if (!"Content-Type".equalsIgnoreCase(name) 290 && !"Content-Id".equalsIgnoreCase(name)) { 291 part.addMimeHeader(name, mh.getValue()); 292 } 293 } 294 } 295 } 296 297 public Source readPayloadAsSource() { 298 access(); 299 return (payload != null) ? new DOMSource(payload) : null; 300 } 301 302 public <T> T readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException { 303 access(); 304 if (payload != null) { 305 if(hasAttachments()) 306 unmarshaller.setAttachmentUnmarshaller(new AttachmentUnmarshallerImpl(getAttachments())); 307 return (T) unmarshaller.unmarshal(payload); 308 309 } 310 return null; 311 } 312 313 /** @deprecated */ 314 public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException { 315 access(); 316 if (payload != null) 317 return bridge.unmarshal(payload,hasAttachments()? new AttachmentUnmarshallerImpl(getAttachments()) : null); 318 return null; 319 } 320 public <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException { 321 access(); 322 if (payload != null) 323 return bridge.unmarshal(payload,hasAttachments()? new AttachmentUnmarshallerImpl(getAttachments()) : null); 324 return null; 325 } 326 327 public XMLStreamReader readPayload() throws XMLStreamException { 328 return soapBodyFirstChildReader(); 329 } 330 331 public void writePayloadTo(XMLStreamWriter sw) throws XMLStreamException { 332 access(); 333 try { 334 for (Element part : bodyParts) 335 DOMUtil.serializeNode(part, sw); 336 } catch (XMLStreamException e) { 337 throw new WebServiceException(e); 338 } 339 } 340 341 public void writeTo(XMLStreamWriter writer) throws XMLStreamException { 342 try { 343 writer.writeStartDocument(); 344 if (!parsedMessage) { 345 DOMUtil.serializeNode(sm.getSOAPPart().getEnvelope(), writer); 346 } else { 347 SOAPEnvelope env = sm.getSOAPPart().getEnvelope(); 348 DOMUtil.writeTagWithAttributes(env, writer); 349 if (hasHeaders()) { 350 if(env.getHeader() != null) { 351 DOMUtil.writeTagWithAttributes(env.getHeader(), writer); 352 } else { 353 writer.writeStartElement(env.getPrefix(), "Header", env.getNamespaceURI()); 354 } 355 for (Header h : headers.asList()) { 356 h.writeTo(writer); 357 } 358 writer.writeEndElement(); 359 } 360 361 DOMUtil.serializeNode(sm.getSOAPBody(), writer); 362 writer.writeEndElement(); 363 } 364 writer.writeEndDocument(); 365 writer.flush(); 366 } catch (SOAPException ex) { 367 throw new XMLStreamException2(ex); 368 //for now. ask jaxws team what to do. 369 } 370 } 371 372 public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler) throws SAXException { 373 String soapNsUri = soapVersion.nsUri; 374 if (!parsedMessage) { 375 DOMScanner ds = new DOMScanner(); 376 ds.setContentHandler(contentHandler); 377 ds.scan(sm.getSOAPPart()); 378 } else { 379 contentHandler.setDocumentLocator(NULL_LOCATOR); 380 contentHandler.startDocument(); 381 contentHandler.startPrefixMapping("S", soapNsUri); 382 startPrefixMapping(contentHandler, envelopeAttrs,"S"); 383 contentHandler.startElement(soapNsUri, "Envelope", "S:Envelope", getAttributes(envelopeAttrs)); 384 if (hasHeaders()) { 385 startPrefixMapping(contentHandler, headerAttrs,"S"); 386 contentHandler.startElement(soapNsUri, "Header", "S:Header", getAttributes(headerAttrs)); 387 MessageHeaders headers = getHeaders(); 388 for (Header h : headers.asList()) { 389 h.writeTo(contentHandler, errorHandler); 390 } 391 endPrefixMapping(contentHandler, headerAttrs,"S"); 392 contentHandler.endElement(soapNsUri, "Header", "S:Header"); 393 394 } 395 startPrefixMapping(contentHandler, bodyAttrs,"S"); 396 // write the body 397 contentHandler.startElement(soapNsUri, "Body", "S:Body", getAttributes(bodyAttrs)); 398 writePayloadTo(contentHandler, errorHandler, true); 399 endPrefixMapping(contentHandler, bodyAttrs,"S"); 400 contentHandler.endElement(soapNsUri, "Body", "S:Body"); 401 endPrefixMapping(contentHandler, envelopeAttrs,"S"); 402 contentHandler.endElement(soapNsUri, "Envelope", "S:Envelope"); 403 } 404 } 405 /** 406 * Gets the Attributes that are not namesapce declarations 407 * @param attrs 408 * @return 409 */ 410 private AttributesImpl getAttributes(NamedNodeMap attrs) { 411 AttributesImpl atts = new AttributesImpl(); 412 if(attrs == null) 413 return EMPTY_ATTS; 414 for(int i=0; i < attrs.getLength();i++) { 415 Attr a = (Attr)attrs.item(i); 416 //check if attr is ns declaration 417 if("xmlns".equals(a.getPrefix()) || "xmlns".equals(a.getLocalName())) { 418 continue; 419 } 420 atts.addAttribute(fixNull(a.getNamespaceURI()),a.getLocalName(),a.getName(),a.getSchemaTypeInfo().getTypeName(),a.getValue()); 421 } 422 return atts; 423 } 424 425 /** 426 * Collects the ns declarations and starts the prefix mapping, consequently the associated endPrefixMapping needs to be called. 427 * @param contentHandler 428 * @param attrs 429 * @param excludePrefix , this is to excldue the global prefix mapping "S" used at the start 430 * @throws SAXException 431 */ 432 private void startPrefixMapping(ContentHandler contentHandler, NamedNodeMap attrs, String excludePrefix) throws SAXException { 433 if(attrs == null) 434 return; 435 for(int i=0; i < attrs.getLength();i++) { 436 Attr a = (Attr)attrs.item(i); 437 //check if attr is ns declaration 438 if("xmlns".equals(a.getPrefix()) || "xmlns".equals(a.getLocalName())) { 439 if(!fixNull(a.getPrefix()).equals(excludePrefix)) { 440 contentHandler.startPrefixMapping(fixNull(a.getPrefix()), a.getNamespaceURI()); 441 } 442 } 443 } 444 } 445 446 private void endPrefixMapping(ContentHandler contentHandler, NamedNodeMap attrs, String excludePrefix) throws SAXException { 447 if(attrs == null) 448 return; 449 for(int i=0; i < attrs.getLength();i++) { 450 Attr a = (Attr)attrs.item(i); 451 //check if attr is ns declaration 452 if("xmlns".equals(a.getPrefix()) || "xmlns".equals(a.getLocalName())) { 453 if(!fixNull(a.getPrefix()).equals(excludePrefix)) { 454 contentHandler.endPrefixMapping(fixNull(a.getPrefix())); 455 } 456 } 457 } 458 } 459 460 private static String fixNull(String s) { 461 if(s==null) return ""; 462 else return s; 463 } 464 465 private void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException { 466 if(fragment) 467 contentHandler = new FragmentContentHandler(contentHandler); 468 DOMScanner ds = new DOMScanner(); 469 ds.setContentHandler(contentHandler); 470 ds.scan(payload); 471 } 472 473 /** 474 * Creates a copy of a {@link com.sun.xml.internal.ws.api.message.Message}. 475 * <p/> 476 * <p/> 477 * This method creates a new {@link com.sun.xml.internal.ws.api.message.Message} whose header/payload/attachments/properties 478 * are identical to this {@link com.sun.xml.internal.ws.api.message.Message}. Once created, the created {@link com.sun.xml.internal.ws.api.message.Message} 479 * and the original {@link com.sun.xml.internal.ws.api.message.Message} behaves independently --- adding header/ 480 * attachment to one {@link com.sun.xml.internal.ws.api.message.Message} doesn't affect another {@link com.sun.xml.internal.ws.api.message.Message} 481 * at all. 482 * <p/> 483 * <h3>Design Rationale</h3> 484 * <p/> 485 * Since a {@link com.sun.xml.internal.ws.api.message.Message} body is read-once, sometimes 486 * (such as when you do fail-over, or WS-RM) you need to 487 * create an idential copy of a {@link com.sun.xml.internal.ws.api.message.Message}. 488 * <p/> 489 * <p/> 490 * The actual copy operation depends on the layout 491 * of the data in memory, hence it's best to be done by 492 * the {@link com.sun.xml.internal.ws.api.message.Message} implementation itself. 493 */ 494 public Message copy() { 495 try { 496 if (!parsedMessage) { 497 return new SAAJMessage(readAsSOAPMessage()); 498 } else { 499 SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); 500 SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); 501 for (Element part : bodyParts) { 502 Node n = newBody.getOwnerDocument().importNode(part, true); 503 newBody.appendChild(n); 504 } 505 addAttributes(newBody, bodyAttrs); 506 return new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); 507 } 508 } catch (SOAPException e) { 509 throw new WebServiceException(e); 510 } 511 } 512 private static final AttributesImpl EMPTY_ATTS = new AttributesImpl(); 513 private static final LocatorImpl NULL_LOCATOR = new LocatorImpl(); 514 515 protected static class SAAJAttachment implements AttachmentEx { 516 517 final AttachmentPart ap; 518 519 String contentIdNoAngleBracket; 520 521 public SAAJAttachment(AttachmentPart part) { 522 this.ap = part; 523 } 524 525 /** 526 * Content ID of the attachment. Uniquely identifies an attachment. 527 */ 528 public String getContentId() { 529 if (contentIdNoAngleBracket == null) { 530 contentIdNoAngleBracket = ap.getContentId(); 531 if (contentIdNoAngleBracket != null && contentIdNoAngleBracket.charAt(0) == '<') 532 contentIdNoAngleBracket = contentIdNoAngleBracket.substring(1, contentIdNoAngleBracket.length()-1); 533 } 534 return contentIdNoAngleBracket; 535 } 536 537 /** 538 * Gets the MIME content-type of this attachment. 539 */ 540 public String getContentType() { 541 return ap.getContentType(); 542 } 543 544 /** 545 * Gets the attachment as an exact-length byte array. 546 */ 547 public byte[] asByteArray() { 548 try { 549 return ap.getRawContentBytes(); 550 } catch (SOAPException e) { 551 throw new WebServiceException(e); 552 } 553 } 554 555 /** 556 * Gets the attachment as a {@link javax.activation.DataHandler}. 557 */ 558 public DataHandler asDataHandler() { 559 try { 560 return ap.getDataHandler(); 561 } catch (SOAPException e) { 562 throw new WebServiceException(e); 563 } 564 } 565 566 /** 567 * Gets the attachment as a {@link javax.xml.transform.Source}. 568 * Note that there's no guarantee that the attachment is actually an XML. 569 */ 570 public Source asSource() { 571 try { 572 return new StreamSource(ap.getRawContent()); 573 } catch (SOAPException e) { 574 throw new WebServiceException(e); 575 } 576 } 577 578 /** 579 * Obtains this attachment as an {@link java.io.InputStream}. 580 */ 581 public InputStream asInputStream() { 582 try { 583 return ap.getRawContent(); 584 } catch (SOAPException e) { 585 throw new WebServiceException(e); 586 } 587 } 588 589 /** 590 * Writes the contents of the attachment into the given stream. 591 */ 592 public void writeTo(OutputStream os) throws IOException { 593 try { 594 ASCIIUtility.copyStream(ap.getRawContent(), os); 595 } catch (SOAPException e) { 596 throw new WebServiceException(e); 597 } 598 } 599 600 /** 601 * Writes this attachment to the given {@link javax.xml.soap.SOAPMessage}. 602 */ 603 public void writeTo(SOAPMessage saaj) { 604 saaj.addAttachmentPart(ap); 605 } 606 607 AttachmentPart asAttachmentPart(){ 608 return ap; 609 } 610 611 public Iterator<MimeHeader> getMimeHeaders() { 612 final Iterator it = ap.getAllMimeHeaders(); 613 return new Iterator<MimeHeader>() { 614 public boolean hasNext() { 615 return it.hasNext(); 616 } 617 618 public MimeHeader next() { 619 final javax.xml.soap.MimeHeader mh = (javax.xml.soap.MimeHeader) it.next(); 620 return new MimeHeader() { 621 public String getName() { 622 return mh.getName(); 623 } 624 625 public String getValue() { 626 return mh.getValue(); 627 } 628 }; 629 } 630 631 public void remove() { 632 throw new UnsupportedOperationException(); 633 } 634 }; 635 } 636 } 637 638 /** 639 * {@link AttachmentSet} for SAAJ. 640 * 641 * SAAJ wants '<' and '>' for the content ID, but {@link AttachmentSet} 642 * doesn't. S this class also does the conversion between them. 643 */ 644 protected static class SAAJAttachmentSet implements AttachmentSet { 645 646 private Map<String, Attachment> attMap; 647 private Iterator attIter; 648 649 public SAAJAttachmentSet(SOAPMessage sm) { 650 attIter = sm.getAttachments(); 651 } 652 653 /** 654 * Gets the attachment by the content ID. 655 * 656 * @return null 657 * if no such attachment exist. 658 */ 659 public Attachment get(String contentId) { 660 // if this is the first time then create the attachment Map 661 if (attMap == null) { 662 if (!attIter.hasNext()) 663 return null; 664 attMap = createAttachmentMap(); 665 } 666 if(contentId.charAt(0) != '<'){ 667 return attMap.get('<'+contentId+'>'); 668 } 669 return attMap.get(contentId); 670 } 671 672 public boolean isEmpty() { 673 if(attMap!=null) 674 return attMap.isEmpty(); 675 else 676 return !attIter.hasNext(); 677 } 678 679 /** 680 * Returns an iterator over a set of elements of type T. 681 * 682 * @return an Iterator. 683 */ 684 public Iterator<Attachment> iterator() { 685 if (attMap == null) { 686 attMap = createAttachmentMap(); 687 } 688 return attMap.values().iterator(); 689 } 690 691 private Map<String, Attachment> createAttachmentMap() { 692 HashMap<String, Attachment> map = new HashMap<String, Attachment>(); 693 while (attIter.hasNext()) { 694 AttachmentPart ap = (AttachmentPart) attIter.next(); 695 map.put(ap.getContentId(), new SAAJAttachment(ap)); 696 } 697 return map; 698 } 699 700 public void add(Attachment att) { 701 attMap.put('<'+att.getContentId()+'>', att); 702 } 703 } 704 705 public SOAPVersion getSOAPVersion() { 706 return soapVersion; 707 } 708 709 private XMLStreamReader soapBodyFirstChildReader; 710 711 /** 712 * This allow the subclass to retain the XMLStreamReader. 713 */ 714 protected XMLStreamReader getXMLStreamReader(SOAPElement soapElement) { 715 return null; 716 } 717 718 protected XMLStreamReader createXMLStreamReader(SOAPElement soapElement) { 719 DOMStreamReader dss = new DOMStreamReader(); 720 dss.setCurrentNode(soapElement); 721 return dss; 722 } 723 724 protected XMLStreamReader soapBodyFirstChildReader() { 725 if (soapBodyFirstChildReader != null) return soapBodyFirstChildReader; 726 soapBodyFirstChild(); 727 if (soapBodyFirstChild != null) { 728 soapBodyFirstChildReader = getXMLStreamReader(soapBodyFirstChild); 729 if (soapBodyFirstChildReader == null) soapBodyFirstChildReader = 730 createXMLStreamReader(soapBodyFirstChild); 731 if (soapBodyFirstChildReader.getEventType() == XMLStreamReader.START_DOCUMENT) { 732 try { 733 while(soapBodyFirstChildReader.getEventType() != XMLStreamReader.START_ELEMENT) 734 soapBodyFirstChildReader.next(); 735 } catch (XMLStreamException e) { 736 throw new RuntimeException(e); 737 } 738 } 739 return soapBodyFirstChildReader; 740 } else { 741 payloadLocalName = null; 742 payloadNamespace = null; 743 return null; 744 } 745 } 746 747 private SOAPElement soapBodyFirstChild; 748 749 SOAPElement soapBodyFirstChild() { 750 if (soapBodyFirstChild != null) return soapBodyFirstChild; 751 try { 752 boolean foundElement = false; 753 for (Node n = sm.getSOAPBody().getFirstChild(); n != null && !foundElement; n = n.getNextSibling()) { 754 if (n.getNodeType() == Node.ELEMENT_NODE) { 755 foundElement = true; 756 if (n instanceof SOAPElement) { 757 soapBodyFirstChild = (SOAPElement) n; 758 payloadLocalName = soapBodyFirstChild.getLocalName(); 759 payloadNamespace = soapBodyFirstChild.getNamespaceURI(); 760 return soapBodyFirstChild; 761 } 762 } 763 } 764 if(foundElement) for(Iterator i = sm.getSOAPBody().getChildElements(); i.hasNext();){ 765 Object o = i.next(); 766 if (o instanceof SOAPElement) { 767 soapBodyFirstChild = (SOAPElement)o; 768 payloadLocalName = soapBodyFirstChild.getLocalName(); 769 payloadNamespace = soapBodyFirstChild.getNamespaceURI(); 770 return soapBodyFirstChild; 771 } 772 } 773 } catch (SOAPException e) { 774 throw new RuntimeException(e); 775 } 776 return soapBodyFirstChild; 777 } 778 }