1/* 2 * Copyright (c) 1997, 2014, 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 26package com.sun.xml.internal.ws.message.saaj; 27 28import com.sun.istack.internal.FragmentContentHandler; 29import com.sun.istack.internal.NotNull; 30import com.sun.istack.internal.Nullable; 31import com.sun.istack.internal.XMLStreamException2; 32import com.sun.xml.internal.bind.api.Bridge; 33import com.sun.xml.internal.bind.unmarshaller.DOMScanner; 34import com.sun.xml.internal.ws.api.SOAPVersion; 35import com.sun.xml.internal.ws.api.message.*; 36import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl; 37import com.sun.xml.internal.ws.spi.db.XMLBridge; 38import com.sun.xml.internal.ws.streaming.DOMStreamReader; 39import com.sun.xml.internal.ws.util.ASCIIUtility; 40import com.sun.xml.internal.ws.util.DOMUtil; 41import org.w3c.dom.Attr; 42import org.w3c.dom.Element; 43import org.w3c.dom.NamedNodeMap; 44import org.w3c.dom.Node; 45import org.xml.sax.ContentHandler; 46import org.xml.sax.ErrorHandler; 47import org.xml.sax.SAXException; 48import org.xml.sax.helpers.AttributesImpl; 49import org.xml.sax.helpers.LocatorImpl; 50 51import javax.activation.DataHandler; 52import javax.xml.bind.JAXBException; 53import javax.xml.bind.Unmarshaller; 54import javax.xml.soap.*; 55import javax.xml.stream.XMLStreamException; 56import javax.xml.stream.XMLStreamReader; 57import javax.xml.stream.XMLStreamWriter; 58import javax.xml.transform.Source; 59import javax.xml.transform.dom.DOMSource; 60import javax.xml.transform.stream.StreamSource; 61import javax.xml.ws.WebServiceException; 62import java.io.IOException; 63import java.io.InputStream; 64import java.io.OutputStream; 65import java.util.HashMap; 66import java.util.Iterator; 67import java.util.List; 68import java.util.Map; 69 70/** 71 * {@link Message} implementation backed by {@link SOAPMessage}. 72 * 73 * @author Vivek Pandey 74 * @author Rama Pulavarthi 75 */ 76public 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 Message result = null; 496 try { 497 access(); 498 if (!parsedMessage) { 499 result = new SAAJMessage(readAsSOAPMessage()); 500 } else { 501 SOAPMessage msg = soapVersion.getMessageFactory().createMessage(); 502 SOAPBody newBody = msg.getSOAPPart().getEnvelope().getBody(); 503 for (Element part : bodyParts) { 504 Node n = newBody.getOwnerDocument().importNode(part, true); 505 newBody.appendChild(n); 506 } 507 addAttributes(newBody, bodyAttrs); 508 result = new SAAJMessage(getHeaders(), getAttachments(), msg, soapVersion); 509 } 510 return result.copyFrom(this); 511 } catch (SOAPException e) { 512 throw new WebServiceException(e); 513 } 514 } 515 private static final AttributesImpl EMPTY_ATTS = new AttributesImpl(); 516 private static final LocatorImpl NULL_LOCATOR = new LocatorImpl(); 517 518 protected static class SAAJAttachment implements AttachmentEx { 519 520 final AttachmentPart ap; 521 522 String contentIdNoAngleBracket; 523 524 public SAAJAttachment(AttachmentPart part) { 525 this.ap = part; 526 } 527 528 /** 529 * Content ID of the attachment. Uniquely identifies an attachment. 530 */ 531 public String getContentId() { 532 if (contentIdNoAngleBracket == null) { 533 contentIdNoAngleBracket = ap.getContentId(); 534 if (contentIdNoAngleBracket != null && contentIdNoAngleBracket.charAt(0) == '<') 535 contentIdNoAngleBracket = contentIdNoAngleBracket.substring(1, contentIdNoAngleBracket.length()-1); 536 } 537 return contentIdNoAngleBracket; 538 } 539 540 /** 541 * Gets the MIME content-type of this attachment. 542 */ 543 public String getContentType() { 544 return ap.getContentType(); 545 } 546 547 /** 548 * Gets the attachment as an exact-length byte array. 549 */ 550 public byte[] asByteArray() { 551 try { 552 return ap.getRawContentBytes(); 553 } catch (SOAPException e) { 554 throw new WebServiceException(e); 555 } 556 } 557 558 /** 559 * Gets the attachment as a {@link javax.activation.DataHandler}. 560 */ 561 public DataHandler asDataHandler() { 562 try { 563 return ap.getDataHandler(); 564 } catch (SOAPException e) { 565 throw new WebServiceException(e); 566 } 567 } 568 569 /** 570 * Gets the attachment as a {@link javax.xml.transform.Source}. 571 * Note that there's no guarantee that the attachment is actually an XML. 572 */ 573 public Source asSource() { 574 try { 575 return new StreamSource(ap.getRawContent()); 576 } catch (SOAPException e) { 577 throw new WebServiceException(e); 578 } 579 } 580 581 /** 582 * Obtains this attachment as an {@link java.io.InputStream}. 583 */ 584 public InputStream asInputStream() { 585 try { 586 return ap.getRawContent(); 587 } catch (SOAPException e) { 588 throw new WebServiceException(e); 589 } 590 } 591 592 /** 593 * Writes the contents of the attachment into the given stream. 594 */ 595 public void writeTo(OutputStream os) throws IOException { 596 try { 597 ASCIIUtility.copyStream(ap.getRawContent(), os); 598 } catch (SOAPException e) { 599 throw new WebServiceException(e); 600 } 601 } 602 603 /** 604 * Writes this attachment to the given {@link javax.xml.soap.SOAPMessage}. 605 */ 606 public void writeTo(SOAPMessage saaj) { 607 saaj.addAttachmentPart(ap); 608 } 609 610 AttachmentPart asAttachmentPart(){ 611 return ap; 612 } 613 614 public Iterator<MimeHeader> getMimeHeaders() { 615 final Iterator it = ap.getAllMimeHeaders(); 616 return new Iterator<MimeHeader>() { 617 public boolean hasNext() { 618 return it.hasNext(); 619 } 620 621 public MimeHeader next() { 622 final javax.xml.soap.MimeHeader mh = (javax.xml.soap.MimeHeader) it.next(); 623 return new MimeHeader() { 624 public String getName() { 625 return mh.getName(); 626 } 627 628 public String getValue() { 629 return mh.getValue(); 630 } 631 }; 632 } 633 634 public void remove() { 635 throw new UnsupportedOperationException(); 636 } 637 }; 638 } 639 } 640 641 /** 642 * {@link AttachmentSet} for SAAJ. 643 * 644 * SAAJ wants '<' and '>' for the content ID, but {@link AttachmentSet} 645 * doesn't. S this class also does the conversion between them. 646 */ 647 protected static class SAAJAttachmentSet implements AttachmentSet { 648 649 private Map<String, Attachment> attMap; 650 private Iterator attIter; 651 652 public SAAJAttachmentSet(SOAPMessage sm) { 653 attIter = sm.getAttachments(); 654 } 655 656 /** 657 * Gets the attachment by the content ID. 658 * 659 * @return null 660 * if no such attachment exist. 661 */ 662 public Attachment get(String contentId) { 663 // if this is the first time then create the attachment Map 664 if (attMap == null) { 665 if (!attIter.hasNext()) 666 return null; 667 attMap = createAttachmentMap(); 668 } 669 if(contentId.charAt(0) != '<'){ 670 return attMap.get('<'+contentId+'>'); 671 } 672 return attMap.get(contentId); 673 } 674 675 public boolean isEmpty() { 676 if(attMap!=null) 677 return attMap.isEmpty(); 678 else 679 return !attIter.hasNext(); 680 } 681 682 /** 683 * Returns an iterator over a set of elements of type T. 684 * 685 * @return an Iterator. 686 */ 687 public Iterator<Attachment> iterator() { 688 if (attMap == null) { 689 attMap = createAttachmentMap(); 690 } 691 return attMap.values().iterator(); 692 } 693 694 private Map<String, Attachment> createAttachmentMap() { 695 HashMap<String, Attachment> map = new HashMap<String, Attachment>(); 696 while (attIter.hasNext()) { 697 AttachmentPart ap = (AttachmentPart) attIter.next(); 698 map.put(ap.getContentId(), new SAAJAttachment(ap)); 699 } 700 return map; 701 } 702 703 public void add(Attachment att) { 704 attMap.put('<'+att.getContentId()+'>', att); 705 } 706 } 707 708 public SOAPVersion getSOAPVersion() { 709 return soapVersion; 710 } 711 712 private XMLStreamReader soapBodyFirstChildReader; 713 714 /** 715 * This allow the subclass to retain the XMLStreamReader. 716 */ 717 protected XMLStreamReader getXMLStreamReader(SOAPElement soapElement) { 718 return null; 719 } 720 721 protected XMLStreamReader createXMLStreamReader(SOAPElement soapElement) { 722 DOMStreamReader dss = new DOMStreamReader(); 723 dss.setCurrentNode(soapElement); 724 return dss; 725 } 726 727 protected XMLStreamReader soapBodyFirstChildReader() { 728 if (soapBodyFirstChildReader != null) return soapBodyFirstChildReader; 729 soapBodyFirstChild(); 730 if (soapBodyFirstChild != null) { 731 soapBodyFirstChildReader = getXMLStreamReader(soapBodyFirstChild); 732 if (soapBodyFirstChildReader == null) soapBodyFirstChildReader = 733 createXMLStreamReader(soapBodyFirstChild); 734 if (soapBodyFirstChildReader.getEventType() == XMLStreamReader.START_DOCUMENT) { 735 try { 736 while(soapBodyFirstChildReader.getEventType() != XMLStreamReader.START_ELEMENT) 737 soapBodyFirstChildReader.next(); 738 } catch (XMLStreamException e) { 739 throw new RuntimeException(e); 740 } 741 } 742 return soapBodyFirstChildReader; 743 } else { 744 payloadLocalName = null; 745 payloadNamespace = null; 746 return null; 747 } 748 } 749 750 private SOAPElement soapBodyFirstChild; 751 752 SOAPElement soapBodyFirstChild() { 753 if (soapBodyFirstChild != null) return soapBodyFirstChild; 754 try { 755 boolean foundElement = false; 756 for (Node n = sm.getSOAPBody().getFirstChild(); n != null && !foundElement; n = n.getNextSibling()) { 757 if (n.getNodeType() == Node.ELEMENT_NODE) { 758 foundElement = true; 759 if (n instanceof SOAPElement) { 760 soapBodyFirstChild = (SOAPElement) n; 761 payloadLocalName = soapBodyFirstChild.getLocalName(); 762 payloadNamespace = soapBodyFirstChild.getNamespaceURI(); 763 return soapBodyFirstChild; 764 } 765 } 766 } 767 if(foundElement) for(Iterator i = sm.getSOAPBody().getChildElements(); i.hasNext();){ 768 Object o = i.next(); 769 if (o instanceof SOAPElement) { 770 soapBodyFirstChild = (SOAPElement)o; 771 payloadLocalName = soapBodyFirstChild.getLocalName(); 772 payloadNamespace = soapBodyFirstChild.getNamespaceURI(); 773 return soapBodyFirstChild; 774 } 775 } 776 } catch (SOAPException e) { 777 throw new RuntimeException(e); 778 } 779 return soapBodyFirstChild; 780 } 781} 782