src/share/jaxws_classes/com/sun/xml/internal/ws/message/stream/StreamMessage.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.ws.message.stream;
ohair@286 27
ohair@286 28 import com.sun.istack.internal.NotNull;
ohair@286 29 import com.sun.istack.internal.Nullable;
ohair@286 30 import com.sun.istack.internal.XMLStreamReaderToContentHandler;
ohair@286 31 import com.sun.xml.internal.bind.api.Bridge;
ohair@286 32 import com.sun.xml.internal.stream.buffer.MutableXMLStreamBuffer;
ohair@286 33 import com.sun.xml.internal.stream.buffer.stax.StreamReaderBufferCreator;
ohair@286 34 import com.sun.xml.internal.ws.api.SOAPVersion;
ohair@286 35 import com.sun.xml.internal.ws.api.message.AttachmentSet;
ohair@286 36 import com.sun.xml.internal.ws.api.message.Header;
ohair@286 37 import com.sun.xml.internal.ws.api.message.HeaderList;
ohair@286 38 import com.sun.xml.internal.ws.api.message.Message;
ohair@286 39 import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory;
ohair@286 40 import com.sun.xml.internal.ws.encoding.TagInfoset;
ohair@286 41 import com.sun.xml.internal.ws.message.AbstractMessageImpl;
ohair@286 42 import com.sun.xml.internal.ws.message.AttachmentUnmarshallerImpl;
ohair@286 43 import com.sun.xml.internal.ws.spi.db.XMLBridge;
ohair@286 44 import com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
ohair@286 45 import com.sun.xml.internal.ws.util.xml.DummyLocation;
ohair@286 46 import com.sun.xml.internal.ws.util.xml.StAXSource;
ohair@286 47 import com.sun.xml.internal.ws.util.xml.XMLStreamReaderToXMLStreamWriter;
ohair@286 48 import org.xml.sax.ContentHandler;
ohair@286 49 import org.xml.sax.ErrorHandler;
ohair@286 50 import org.xml.sax.SAXException;
ohair@286 51 import org.xml.sax.SAXParseException;
ohair@286 52 import org.xml.sax.helpers.NamespaceSupport;
ohair@286 53
ohair@286 54 import javax.xml.bind.JAXBException;
ohair@286 55 import javax.xml.bind.Unmarshaller;
ohair@286 56 import javax.xml.stream.*;
ohair@286 57 import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
ohair@286 58 import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
ohair@286 59 import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
ohair@286 60 import javax.xml.transform.Source;
ohair@286 61 import javax.xml.ws.WebServiceException;
ohair@286 62 import java.util.ArrayList;
ohair@286 63 import java.util.Enumeration;
ohair@286 64 import java.util.List;
ohair@286 65
ohair@286 66 /**
ohair@286 67 * {@link Message} implementation backed by {@link XMLStreamReader}.
ohair@286 68 *
ohair@286 69 * TODO: we need another message class that keeps {@link XMLStreamReader} that points
ohair@286 70 * at the start of the envelope element.
ohair@286 71 */
ohair@286 72 public final class StreamMessage extends AbstractMessageImpl {
ohair@286 73 /**
ohair@286 74 * The reader will be positioned at
ohair@286 75 * the first child of the SOAP body
ohair@286 76 */
ohair@286 77 private @NotNull XMLStreamReader reader;
ohair@286 78
ohair@286 79 // lazily created
ohair@286 80 private @Nullable HeaderList headers;
ohair@286 81
ohair@286 82 /**
ohair@286 83 * Because the StreamMessage leaves out the white spaces around payload
ohair@286 84 * when being instantiated the space characters between soap:Body opening and
ohair@286 85 * payload is stored in this field to be reused later (necessary for message security);
ohair@286 86 * Instantiated after StreamMessage creation
ohair@286 87 */
ohair@286 88 private String bodyPrologue = null;
ohair@286 89
ohair@286 90 /**
ohair@286 91 * instantiated after writing message to XMLStreamWriter
ohair@286 92 */
ohair@286 93 private String bodyEpilogue = null;
ohair@286 94
ohair@286 95 private final String payloadLocalName;
ohair@286 96
ohair@286 97 private final String payloadNamespaceURI;
ohair@286 98
ohair@286 99 /**
ohair@286 100 * infoset about the SOAP envelope, header, and body.
ohair@286 101 *
ohair@286 102 * <p>
ohair@286 103 * If the creater of this object didn't care about those,
ohair@286 104 * we use stock values.
ohair@286 105 */
ohair@286 106 private @NotNull TagInfoset envelopeTag,headerTag,bodyTag;
ohair@286 107
ohair@286 108 /**
ohair@286 109 * Used only for debugging. This records where the message was consumed.
ohair@286 110 */
ohair@286 111 private Throwable consumedAt;
ohair@286 112
ohair@286 113 /**
ohair@286 114 * Default s:Envelope, s:Header, and s:Body tag infoset definitions.
ohair@286 115 *
ohair@286 116 * We need 3 for SOAP 1.1, 3 for SOAP 1.2.
ohair@286 117 */
ohair@286 118 private static final TagInfoset[] DEFAULT_TAGS;
ohair@286 119
ohair@286 120 static {
ohair@286 121 DEFAULT_TAGS = new TagInfoset[6];
ohair@286 122 create(SOAPVersion.SOAP_11);
ohair@286 123 create(SOAPVersion.SOAP_12);
ohair@286 124 }
ohair@286 125
ohair@286 126 /**
ohair@286 127 * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
ohair@286 128 * that points at the start element of the payload, and headers.
ohair@286 129 *
ohair@286 130 * <p>
ohair@286 131 * This method creaets a {@link Message} from a payload.
ohair@286 132 *
ohair@286 133 * @param headers
ohair@286 134 * if null, it means no headers. if non-null,
ohair@286 135 * it will be owned by this message.
ohair@286 136 * @param reader
ohair@286 137 * points at the start element/document of the payload (or the end element of the &lt;s:Body>
ohair@286 138 * if there's no payload)
ohair@286 139 */
ohair@286 140 public StreamMessage(@Nullable HeaderList headers, @NotNull AttachmentSet attachmentSet, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
ohair@286 141 super(soapVersion);
ohair@286 142 this.headers = headers;
ohair@286 143 this.attachmentSet = attachmentSet;
ohair@286 144 this.reader = reader;
ohair@286 145
ohair@286 146 if(reader.getEventType()== START_DOCUMENT)
ohair@286 147 XMLStreamReaderUtil.nextElementContent(reader);
ohair@286 148
ohair@286 149 //if the reader is pointing to the end element </soapenv:Body> then its empty message
ohair@286 150 // or no payload
ohair@286 151 if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
ohair@286 152 String body = reader.getLocalName();
ohair@286 153 String nsUri = reader.getNamespaceURI();
ohair@286 154 assert body != null;
ohair@286 155 assert nsUri != null;
ohair@286 156 //if its not soapenv:Body then throw exception, we received malformed stream
ohair@286 157 if(body.equals("Body") && nsUri.equals(soapVersion.nsUri)){
ohair@286 158 this.payloadLocalName = null;
ohair@286 159 this.payloadNamespaceURI = null;
ohair@286 160 }else{ //TODO: i18n and also we should be throwing better message that this
ohair@286 161 throw new WebServiceException("Malformed stream: {"+nsUri+"}"+body);
ohair@286 162 }
ohair@286 163 }else{
ohair@286 164 this.payloadLocalName = reader.getLocalName();
ohair@286 165 this.payloadNamespaceURI = reader.getNamespaceURI();
ohair@286 166 }
ohair@286 167
ohair@286 168 // use the default infoset representation for headers
ohair@286 169 int base = soapVersion.ordinal()*3;
ohair@286 170 this.envelopeTag = DEFAULT_TAGS[base];
ohair@286 171 this.headerTag = DEFAULT_TAGS[base+1];
ohair@286 172 this.bodyTag = DEFAULT_TAGS[base+2];
ohair@286 173 }
ohair@286 174
ohair@286 175 /**
ohair@286 176 * Creates a {@link StreamMessage} from a {@link XMLStreamReader}
ohair@286 177 * and the complete infoset of the SOAP envelope.
ohair@286 178 *
ohair@286 179 * <p>
ohair@286 180 * See {@link #StreamMessage(HeaderList, AttachmentSet, XMLStreamReader, SOAPVersion)} for
ohair@286 181 * the description of the basic parameters.
ohair@286 182 *
ohair@286 183 * @param headerTag
ohair@286 184 * Null if the message didn't have a header tag.
ohair@286 185 *
ohair@286 186 */
ohair@286 187 public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable HeaderList headers, @NotNull TagInfoset bodyTag, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
ohair@286 188 this(envelopeTag, headerTag, attachmentSet, headers, null, bodyTag, null, reader, soapVersion);
ohair@286 189 }
ohair@286 190
ohair@286 191 public StreamMessage(@NotNull TagInfoset envelopeTag, @Nullable TagInfoset headerTag, @NotNull AttachmentSet attachmentSet, @Nullable HeaderList headers, @Nullable String bodyPrologue, @NotNull TagInfoset bodyTag, @Nullable String bodyEpilogue, @NotNull XMLStreamReader reader, @NotNull SOAPVersion soapVersion) {
ohair@286 192 this(headers,attachmentSet,reader,soapVersion);
ohair@286 193 if(envelopeTag == null ) {
ohair@286 194 throw new IllegalArgumentException("EnvelopeTag TagInfoset cannot be null");
ohair@286 195 }
ohair@286 196 if(bodyTag == null ) {
ohair@286 197 throw new IllegalArgumentException("BodyTag TagInfoset cannot be null");
ohair@286 198 }
ohair@286 199 this.envelopeTag = envelopeTag;
ohair@286 200 this.headerTag = headerTag!=null ? headerTag :
ohair@286 201 new TagInfoset(envelopeTag.nsUri,"Header",envelopeTag.prefix,EMPTY_ATTS);
ohair@286 202 this.bodyTag = bodyTag;
ohair@286 203 this.bodyPrologue = bodyPrologue;
ohair@286 204 this.bodyEpilogue = bodyEpilogue;
ohair@286 205 }
ohair@286 206
ohair@286 207 public boolean hasHeaders() {
ohair@286 208 return headers!=null && !headers.isEmpty();
ohair@286 209 }
ohair@286 210
ohair@286 211 public HeaderList getHeaders() {
ohair@286 212 if (headers == null) {
ohair@286 213 headers = new HeaderList();
ohair@286 214 }
ohair@286 215 return headers;
ohair@286 216 }
ohair@286 217
ohair@286 218 public String getPayloadLocalPart() {
ohair@286 219 return payloadLocalName;
ohair@286 220 }
ohair@286 221
ohair@286 222 public String getPayloadNamespaceURI() {
ohair@286 223 return payloadNamespaceURI;
ohair@286 224 }
ohair@286 225
ohair@286 226 public boolean hasPayload() {
ohair@286 227 return payloadLocalName!=null;
ohair@286 228 }
ohair@286 229
ohair@286 230 public Source readPayloadAsSource() {
ohair@286 231 if(hasPayload()) {
ohair@286 232 assert unconsumed();
ohair@286 233 return new StAXSource(reader, true, getInscopeNamespaces());
ohair@286 234 } else
ohair@286 235 return null;
ohair@286 236 }
ohair@286 237
ohair@286 238 /**
ohair@286 239 * There is no way to enumerate inscope namespaces for XMLStreamReader. That means
ohair@286 240 * namespaces declared in envelope, and body tags need to be computed using their
ohair@286 241 * {@link TagInfoset}s.
ohair@286 242 *
ohair@286 243 * @return array of the even length of the form { prefix0, uri0, prefix1, uri1, ... }
ohair@286 244 */
ohair@286 245 private String[] getInscopeNamespaces() {
ohair@286 246 NamespaceSupport nss = new NamespaceSupport();
ohair@286 247
ohair@286 248 nss.pushContext();
ohair@286 249 for(int i=0; i < envelopeTag.ns.length; i+=2) {
ohair@286 250 nss.declarePrefix(envelopeTag.ns[i], envelopeTag.ns[i+1]);
ohair@286 251 }
ohair@286 252
ohair@286 253 nss.pushContext();
ohair@286 254 for(int i=0; i < bodyTag.ns.length; i+=2) {
ohair@286 255 nss.declarePrefix(bodyTag.ns[i], bodyTag.ns[i+1]);
ohair@286 256 }
ohair@286 257
ohair@286 258 List<String> inscope = new ArrayList<String>();
ohair@286 259 for( Enumeration en = nss.getPrefixes(); en.hasMoreElements(); ) {
ohair@286 260 String prefix = (String)en.nextElement();
ohair@286 261 inscope.add(prefix);
ohair@286 262 inscope.add(nss.getURI(prefix));
ohair@286 263 }
ohair@286 264 return inscope.toArray(new String[inscope.size()]);
ohair@286 265 }
ohair@286 266
ohair@286 267 public Object readPayloadAsJAXB(Unmarshaller unmarshaller) throws JAXBException {
ohair@286 268 if(!hasPayload())
ohair@286 269 return null;
ohair@286 270 assert unconsumed();
ohair@286 271 // TODO: How can the unmarshaller process this as a fragment?
ohair@286 272 if(hasAttachments())
ohair@286 273 unmarshaller.setAttachmentUnmarshaller(new AttachmentUnmarshallerImpl(getAttachments()));
ohair@286 274 try {
ohair@286 275 return unmarshaller.unmarshal(reader);
ohair@286 276 } finally{
ohair@286 277 unmarshaller.setAttachmentUnmarshaller(null);
ohair@286 278 XMLStreamReaderUtil.readRest(reader);
ohair@286 279 XMLStreamReaderUtil.close(reader);
ohair@286 280 XMLStreamReaderFactory.recycle(reader);
ohair@286 281 }
ohair@286 282 }
ohair@286 283 /** @deprecated */
ohair@286 284 public <T> T readPayloadAsJAXB(Bridge<T> bridge) throws JAXBException {
ohair@286 285 if(!hasPayload())
ohair@286 286 return null;
ohair@286 287 assert unconsumed();
ohair@286 288 T r = bridge.unmarshal(reader,
ohair@286 289 hasAttachments() ? new AttachmentUnmarshallerImpl(getAttachments()) : null);
ohair@286 290 XMLStreamReaderUtil.readRest(reader);
ohair@286 291 XMLStreamReaderUtil.close(reader);
ohair@286 292 XMLStreamReaderFactory.recycle(reader);
ohair@286 293 return r;
ohair@286 294 }
ohair@286 295
ohair@286 296 public <T> T readPayloadAsJAXB(XMLBridge<T> bridge) throws JAXBException {
ohair@286 297 if(!hasPayload())
ohair@286 298 return null;
ohair@286 299 assert unconsumed();
ohair@286 300 T r = bridge.unmarshal(reader,
ohair@286 301 hasAttachments() ? new AttachmentUnmarshallerImpl(getAttachments()) : null);
ohair@286 302 XMLStreamReaderUtil.readRest(reader);
ohair@286 303 XMLStreamReaderUtil.close(reader);
ohair@286 304 XMLStreamReaderFactory.recycle(reader);
ohair@286 305 return r;
ohair@286 306 }
ohair@286 307
ohair@286 308 @Override
ohair@286 309 public void consume() {
ohair@286 310 assert unconsumed();
ohair@286 311 XMLStreamReaderUtil.readRest(reader);
ohair@286 312 XMLStreamReaderUtil.close(reader);
ohair@286 313 XMLStreamReaderFactory.recycle(reader);
ohair@286 314 }
ohair@286 315
ohair@286 316 public XMLStreamReader readPayload() {
ohair@286 317 if(!hasPayload())
ohair@286 318 return null;
ohair@286 319 // TODO: What about access at and beyond </soap:Body>
ohair@286 320 assert unconsumed();
ohair@286 321 return this.reader;
ohair@286 322 }
ohair@286 323
ohair@286 324 public void writePayloadTo(XMLStreamWriter writer)throws XMLStreamException {
ohair@286 325 assert unconsumed();
ohair@286 326
ohair@286 327 if(payloadLocalName==null) {
ohair@286 328 return; // no body
ohair@286 329 }
ohair@286 330
ohair@286 331 if (bodyPrologue != null) {
ohair@286 332 writer.writeCharacters(bodyPrologue);
ohair@286 333 }
ohair@286 334
ohair@286 335 XMLStreamReaderToXMLStreamWriter conv = new XMLStreamReaderToXMLStreamWriter();
ohair@286 336
ohair@286 337 while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
ohair@286 338 String name = reader.getLocalName();
ohair@286 339 String nsUri = reader.getNamespaceURI();
ohair@286 340
ohair@286 341 // After previous conv.bridge() call the cursor will be at END_ELEMENT.
ohair@286 342 // Check if its not soapenv:Body then move to next ELEMENT
ohair@286 343 if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
ohair@286 344
ohair@286 345 if (!isBodyElement(name, nsUri)){
ohair@286 346 // closing payload element: store epilogue for further signing, if applicable
ohair@286 347 // however if there more than one payloads exist - the last one is stored
ohair@286 348 String whiteSpaces = XMLStreamReaderUtil.nextWhiteSpaceContent(reader);
ohair@286 349 if (whiteSpaces != null) {
ohair@286 350 this.bodyEpilogue = whiteSpaces;
ohair@286 351 // write it to the message too
ohair@286 352 writer.writeCharacters(whiteSpaces);
ohair@286 353 }
ohair@286 354 } else {
ohair@286 355 // body closed > exit
ohair@286 356 break;
ohair@286 357 }
ohair@286 358
ohair@286 359 } else {
ohair@286 360 // payload opening element: copy payload to writer
ohair@286 361 conv.bridge(reader,writer);
ohair@286 362 }
ohair@286 363 }
ohair@286 364
ohair@286 365 XMLStreamReaderUtil.readRest(reader);
ohair@286 366 XMLStreamReaderUtil.close(reader);
ohair@286 367 XMLStreamReaderFactory.recycle(reader);
ohair@286 368 }
ohair@286 369
ohair@286 370 private boolean isBodyElement(String name, String nsUri) {
ohair@286 371 return name.equals("Body") && nsUri.equals(soapVersion.nsUri);
ohair@286 372 }
ohair@286 373
ohair@286 374 public void writeTo(XMLStreamWriter sw) throws XMLStreamException{
ohair@286 375 writeEnvelope(sw);
ohair@286 376 }
ohair@286 377
ohair@286 378 /**
ohair@286 379 * This method should be called when the StreamMessage is created with a payload
ohair@286 380 * @param writer
ohair@286 381 */
ohair@286 382 private void writeEnvelope(XMLStreamWriter writer) throws XMLStreamException {
ohair@286 383 writer.writeStartDocument();
ohair@286 384 envelopeTag.writeStart(writer);
ohair@286 385
ohair@286 386 //write headers
ohair@286 387 HeaderList hl = getHeaders();
ohair@286 388 if(hl.size() > 0){
ohair@286 389 headerTag.writeStart(writer);
ohair@286 390 for(Header h:hl){
ohair@286 391 h.writeTo(writer);
ohair@286 392 }
ohair@286 393 writer.writeEndElement();
ohair@286 394 }
ohair@286 395 bodyTag.writeStart(writer);
ohair@286 396 if(hasPayload())
ohair@286 397 writePayloadTo(writer);
ohair@286 398 writer.writeEndElement();
ohair@286 399 writer.writeEndElement();
ohair@286 400 writer.writeEndDocument();
ohair@286 401 }
ohair@286 402
ohair@286 403 public void writePayloadTo(ContentHandler contentHandler, ErrorHandler errorHandler, boolean fragment) throws SAXException {
ohair@286 404 assert unconsumed();
ohair@286 405
ohair@286 406 try {
ohair@286 407 if(payloadLocalName==null)
ohair@286 408 return; // no body
ohair@286 409
ohair@286 410 if (bodyPrologue != null) {
ohair@286 411 char[] chars = bodyPrologue.toCharArray();
ohair@286 412 contentHandler.characters(chars, 0, chars.length);
ohair@286 413 }
ohair@286 414
ohair@286 415 XMLStreamReaderToContentHandler conv = new XMLStreamReaderToContentHandler(reader,contentHandler,true,fragment,getInscopeNamespaces());
ohair@286 416
ohair@286 417 while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
ohair@286 418 String name = reader.getLocalName();
ohair@286 419 String nsUri = reader.getNamespaceURI();
ohair@286 420
ohair@286 421 // After previous conv.bridge() call the cursor will be at END_ELEMENT.
ohair@286 422 // Check if its not soapenv:Body then move to next ELEMENT
ohair@286 423 if(reader.getEventType() == XMLStreamConstants.END_ELEMENT){
ohair@286 424
ohair@286 425 if (!isBodyElement(name, nsUri)){
ohair@286 426 // closing payload element: store epilogue for further signing, if applicable
ohair@286 427 // however if there more than one payloads exist - the last one is stored
ohair@286 428 String whiteSpaces = XMLStreamReaderUtil.nextWhiteSpaceContent(reader);
ohair@286 429 if (whiteSpaces != null) {
ohair@286 430 this.bodyEpilogue = whiteSpaces;
ohair@286 431 // write it to the message too
ohair@286 432 char[] chars = whiteSpaces.toCharArray();
ohair@286 433 contentHandler.characters(chars, 0, chars.length);
ohair@286 434 }
ohair@286 435 } else {
ohair@286 436 // body closed > exit
ohair@286 437 break;
ohair@286 438 }
ohair@286 439
ohair@286 440 } else {
ohair@286 441 // payload opening element: copy payload to writer
ohair@286 442 conv.bridge();
ohair@286 443 }
ohair@286 444 }
ohair@286 445 XMLStreamReaderUtil.readRest(reader);
ohair@286 446 XMLStreamReaderUtil.close(reader);
ohair@286 447 XMLStreamReaderFactory.recycle(reader);
ohair@286 448 } catch (XMLStreamException e) {
ohair@286 449 Location loc = e.getLocation();
ohair@286 450 if(loc==null) loc = DummyLocation.INSTANCE;
ohair@286 451
ohair@286 452 SAXParseException x = new SAXParseException(
ohair@286 453 e.getMessage(),loc.getPublicId(),loc.getSystemId(),loc.getLineNumber(),loc.getColumnNumber(),e);
ohair@286 454 errorHandler.error(x);
ohair@286 455 }
ohair@286 456 }
ohair@286 457
ohair@286 458 // TODO: this method should be probably rewritten to respect spaces between eelements; is it used at all?
ohair@286 459 public Message copy() {
ohair@286 460 try {
ohair@286 461 assert unconsumed();
ohair@286 462 consumedAt = null; // but we don't want to mark it as consumed
ohair@286 463 MutableXMLStreamBuffer xsb = new MutableXMLStreamBuffer();
ohair@286 464 StreamReaderBufferCreator c = new StreamReaderBufferCreator(xsb);
ohair@286 465
ohair@286 466 // preserving inscope namespaces from envelope, and body. Other option
ohair@286 467 // would be to create a filtering XMLStreamReader from reader+envelopeTag+bodyTag
ohair@286 468 c.storeElement(envelopeTag.nsUri, envelopeTag.localName, envelopeTag.prefix, envelopeTag.ns);
ohair@286 469 c.storeElement(bodyTag.nsUri, bodyTag.localName, bodyTag.prefix, bodyTag.ns);
ohair@286 470
ohair@286 471 if (hasPayload()) {
ohair@286 472 // Loop all the way for multi payload case
ohair@286 473 while(reader.getEventType() != XMLStreamConstants.END_DOCUMENT){
ohair@286 474 String name = reader.getLocalName();
ohair@286 475 String nsUri = reader.getNamespaceURI();
ohair@286 476 if(isBodyElement(name, nsUri) || (reader.getEventType() == XMLStreamConstants.END_DOCUMENT))
ohair@286 477 break;
ohair@286 478 c.create(reader);
ohair@286 479
ohair@286 480 // Skip whitespaces in between payload and </Body> or between elements
ohair@286 481 // those won't be in the message itself, but we store them in field bodyEpilogue
ohair@286 482 if (reader.isWhiteSpace()) {
ohair@286 483 bodyEpilogue = XMLStreamReaderUtil.currentWhiteSpaceContent(reader);
ohair@286 484 } else {
ohair@286 485 // clear it in case the existing was not the last one
ohair@286 486 // (we are interested only in the last one?)
ohair@286 487 bodyEpilogue = null;
ohair@286 488 }
ohair@286 489 }
ohair@286 490 }
ohair@286 491 c.storeEndElement(); // create structure element for </Body>
ohair@286 492 c.storeEndElement(); // create structure element for </Envelope>
ohair@286 493 c.storeEndElement(); // create structure element for END_DOCUMENT
ohair@286 494
ohair@286 495 XMLStreamReaderUtil.readRest(reader);
ohair@286 496 XMLStreamReaderUtil.close(reader);
ohair@286 497 XMLStreamReaderFactory.recycle(reader);
ohair@286 498
ohair@286 499 reader = xsb.readAsXMLStreamReader();
ohair@286 500 XMLStreamReader clone = xsb.readAsXMLStreamReader();
ohair@286 501
ohair@286 502 // advance to the start tag of the <Body> first child element
ohair@286 503 proceedToRootElement(reader);
ohair@286 504 proceedToRootElement(clone);
ohair@286 505
ohair@286 506 return new StreamMessage(envelopeTag, headerTag, attachmentSet, HeaderList.copy(headers), bodyPrologue, bodyTag, bodyEpilogue, clone, soapVersion);
ohair@286 507 } catch (XMLStreamException e) {
ohair@286 508 throw new WebServiceException("Failed to copy a message",e);
ohair@286 509 }
ohair@286 510 }
ohair@286 511
ohair@286 512 private void proceedToRootElement(XMLStreamReader xsr) throws XMLStreamException {
ohair@286 513 assert xsr.getEventType()==START_DOCUMENT;
ohair@286 514 xsr.nextTag();
ohair@286 515 xsr.nextTag();
ohair@286 516 xsr.nextTag();
ohair@286 517 assert xsr.getEventType()==START_ELEMENT || xsr.getEventType()==END_ELEMENT;
ohair@286 518 }
ohair@286 519
ohair@286 520 public void writeTo(ContentHandler contentHandler, ErrorHandler errorHandler ) throws SAXException {
ohair@286 521 contentHandler.setDocumentLocator(NULL_LOCATOR);
ohair@286 522 contentHandler.startDocument();
ohair@286 523 envelopeTag.writeStart(contentHandler);
ohair@286 524 headerTag.writeStart(contentHandler);
ohair@286 525 if(hasHeaders()) {
ohair@286 526 HeaderList headers = getHeaders();
ohair@286 527 int len = headers.size();
ohair@286 528 for( int i=0; i<len; i++ ) {
ohair@286 529 // shouldn't JDK be smart enough to use array-style indexing for this foreach!?
ohair@286 530 headers.get(i).writeTo(contentHandler,errorHandler);
ohair@286 531 }
ohair@286 532 }
ohair@286 533 headerTag.writeEnd(contentHandler);
ohair@286 534 bodyTag.writeStart(contentHandler);
ohair@286 535 writePayloadTo(contentHandler,errorHandler, true);
ohair@286 536 bodyTag.writeEnd(contentHandler);
ohair@286 537 envelopeTag.writeEnd(contentHandler);
ohair@286 538 contentHandler.endDocument();
ohair@286 539 }
ohair@286 540
ohair@286 541 /**
ohair@286 542 * Used for an assertion. Returns true when the message is unconsumed,
ohair@286 543 * or otherwise throw an exception.
ohair@286 544 *
ohair@286 545 * <p>
ohair@286 546 * Calling this method also marks the stream as 'consumed'
ohair@286 547 */
ohair@286 548 private boolean unconsumed() {
ohair@286 549 if(payloadLocalName==null)
ohair@286 550 return true; // no payload. can be consumed multiple times.
ohair@286 551
ohair@286 552 if(reader.getEventType()!=XMLStreamReader.START_ELEMENT) {
ohair@286 553 AssertionError error = new AssertionError("StreamMessage has been already consumed. See the nested exception for where it's consumed");
ohair@286 554 error.initCause(consumedAt);
ohair@286 555 throw error;
ohair@286 556 }
ohair@286 557 consumedAt = new Exception().fillInStackTrace();
ohair@286 558 return true;
ohair@286 559 }
ohair@286 560
ohair@286 561 private static void create(SOAPVersion v) {
ohair@286 562 int base = v.ordinal()*3;
ohair@286 563 DEFAULT_TAGS[base ] = new TagInfoset(v.nsUri,"Envelope","S",EMPTY_ATTS,"S",v.nsUri);
ohair@286 564 DEFAULT_TAGS[base+1] = new TagInfoset(v.nsUri,"Header","S",EMPTY_ATTS);
ohair@286 565 DEFAULT_TAGS[base+2] = new TagInfoset(v.nsUri,"Body","S",EMPTY_ATTS);
ohair@286 566 }
ohair@286 567
ohair@286 568 public String getBodyPrologue() {
ohair@286 569 return bodyPrologue;
ohair@286 570 }
ohair@286 571
ohair@286 572 public String getBodyEpilogue() {
ohair@286 573 return bodyEpilogue;
ohair@286 574 }
ohair@286 575
ohair@286 576 }

mercurial