1/* 2 * Copyright (c) 1997, 2017, 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.messaging.saaj.soap.impl; 27 28import java.io.IOException; 29import java.io.OutputStream; 30import java.io.OutputStreamWriter; 31 32import java.util.logging.Level; 33 34import javax.xml.namespace.QName; 35import javax.xml.soap.*; 36import javax.xml.stream.XMLStreamException; 37import javax.xml.stream.XMLStreamReader; 38import javax.xml.stream.XMLStreamWriter; 39import javax.xml.transform.*; 40import javax.xml.transform.dom.DOMSource; 41import javax.xml.transform.stream.StreamResult; 42 43import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; 44import com.sun.xml.internal.messaging.saaj.soap.LazyEnvelope; 45import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; 46import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; 47import com.sun.xml.internal.messaging.saaj.soap.StaxLazySourceBridge; 48import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; 49import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; 50import com.sun.xml.internal.messaging.saaj.util.stax.LazyEnvelopeStaxReader; 51import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; 52 53import com.sun.xml.internal.org.jvnet.staxex.util.DOMStreamReader; 54import com.sun.xml.internal.org.jvnet.staxex.util.XMLStreamReaderToXMLStreamWriter; 55import org.w3c.dom.Element; 56 57/** 58 * Our implementation of the SOAP envelope. 59 * 60 * @author Anil Vijendran (anil@sun.com) 61 */ 62public abstract class EnvelopeImpl extends ElementImpl implements LazyEnvelope { 63 protected HeaderImpl header; 64 protected BodyImpl body; 65 String omitXmlDecl = "yes"; 66 String charset = "utf-8"; 67 String xmlDecl = null; 68 69 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, Name name) { 70 super(ownerDoc, name); 71 } 72 73 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, QName name) { 74 super(ownerDoc, name); 75 } 76 77 protected EnvelopeImpl( 78 SOAPDocumentImpl ownerDoc, 79 NameImpl name, 80 boolean createHeader, 81 boolean createBody) 82 throws SOAPException { 83 this(ownerDoc, name); 84 85 ensureNamespaceIsDeclared( 86 getElementQName().getPrefix(), getElementQName().getNamespaceURI()); 87 88 // XXX 89 if (createHeader) 90 addHeader(); 91 92 if (createBody) 93 addBody(); 94 } 95 96 public EnvelopeImpl(SOAPDocumentImpl ownerDoc, Element domElement) { 97 super(ownerDoc, domElement); 98 } 99 100 protected abstract NameImpl getHeaderName(String prefix); 101 protected abstract NameImpl getBodyName(String prefix); 102 103 @Override 104 public SOAPHeader addHeader() throws SOAPException { 105 return addHeader(null); 106 } 107 108 public SOAPHeader addHeader(String prefix) throws SOAPException { 109 110 if (prefix == null || prefix.equals("")) { 111 prefix = getPrefix(); 112 } 113 114 NameImpl headerName = getHeaderName(prefix); 115 NameImpl bodyName = getBodyName(prefix); 116 117 HeaderImpl header = null; 118 SOAPElement firstChild = (SOAPElement) getFirstChildElement(); 119 120 if (firstChild != null) { 121 if (firstChild.getElementName().equals(headerName)) { 122 log.severe("SAAJ0120.impl.header.already.exists"); 123 throw new SOAPExceptionImpl("Can't add a header when one is already present."); 124 } else if (!firstChild.getElementName().equals(bodyName)) { 125 log.severe("SAAJ0121.impl.invalid.first.child.of.envelope"); 126 throw new SOAPExceptionImpl("First child of Envelope must be either a Header or Body"); 127 } 128 } 129 130 header = (HeaderImpl) createElement(headerName); 131 insertBefore(header.getDomElement(), firstChild); 132 header.ensureNamespaceIsDeclared(headerName.getPrefix(), headerName.getURI()); 133 134 return header; 135 } 136 137 protected void lookForHeader() throws SOAPException { 138 NameImpl headerName = getHeaderName(null); 139 140 HeaderImpl hdr = (HeaderImpl) findChild(headerName); 141 header = hdr; 142 } 143 144 @Override 145 public SOAPHeader getHeader() throws SOAPException { 146 lookForHeader(); 147 return header; 148 } 149 150 protected void lookForBody() throws SOAPException { 151 NameImpl bodyName = getBodyName(null); 152 153 BodyImpl bodyChildElement = (BodyImpl) findChild(bodyName); 154 body = bodyChildElement; 155 } 156 157 @Override 158 public SOAPBody addBody() throws SOAPException { 159 return addBody(null); 160 } 161 162 public SOAPBody addBody(String prefix) throws SOAPException { 163 lookForBody(); 164 165 if (prefix == null || prefix.equals("")) { 166 prefix = getPrefix(); 167 } 168 169 if (body == null) { 170 NameImpl bodyName = getBodyName(prefix); 171 body = (BodyImpl) createElement(bodyName); 172 insertBefore(body.getDomElement(), null); 173 body.ensureNamespaceIsDeclared(bodyName.getPrefix(), bodyName.getURI()); 174 } else { 175 log.severe("SAAJ0122.impl.body.already.exists"); 176 throw new SOAPExceptionImpl("Can't add a body when one is already present."); 177 } 178 179 return body; 180 } 181 182 @Override 183 protected SOAPElement addElement(Name name) throws SOAPException { 184 if (getBodyName(null).equals(name)) { 185 return addBody(name.getPrefix()); 186 } 187 if (getHeaderName(null).equals(name)) { 188 return addHeader(name.getPrefix()); 189 } 190 191 return super.addElement(name); 192 } 193 194 @Override 195 protected SOAPElement addElement(QName name) throws SOAPException { 196 if (getBodyName(null).equals(NameImpl.convertToName(name))) { 197 return addBody(name.getPrefix()); 198 } 199 if (getHeaderName(null).equals(NameImpl.convertToName(name))) { 200 return addHeader(name.getPrefix()); 201 } 202 203 return super.addElement(name); 204 } 205 206 @Override 207 public SOAPBody getBody() throws SOAPException { 208 lookForBody(); 209 return body; 210 } 211 212 @Override 213 public Source getContent() { 214 return new DOMSource(getOwnerDocument()); 215 } 216 217 @Override 218 public Name createName(String localName, String prefix, String uri) 219 throws SOAPException { 220 221 // validating parameters before passing them on 222 // to make sure that the namespace specification rules are followed 223 224 // reserved xmlns prefix cannot be used. 225 if ("xmlns".equals(prefix)) { 226 log.severe("SAAJ0123.impl.no.reserved.xmlns"); 227 throw new SOAPExceptionImpl("Cannot declare reserved xmlns prefix"); 228 } 229 // Qualified name cannot be xmlns. 230 if ((prefix == null) && ("xmlns".equals(localName))) { 231 log.severe("SAAJ0124.impl.qualified.name.cannot.be.xmlns"); 232 throw new SOAPExceptionImpl("Qualified name cannot be xmlns"); 233 } 234 235 return NameImpl.create(localName, prefix, uri); 236 } 237 238 public Name createName(String localName, String prefix) 239 throws SOAPException { 240 String namespace = getNamespaceURI(prefix); 241 if (namespace == null) { 242 log.log( 243 Level.SEVERE, 244 "SAAJ0126.impl.cannot.locate.ns", 245 new String[] { prefix }); 246 throw new SOAPExceptionImpl( 247 "Unable to locate namespace for prefix " + prefix); 248 } 249 return NameImpl.create(localName, prefix, namespace); 250 } 251 252 @Override 253 public Name createName(String localName) throws SOAPException { 254 return NameImpl.createFromUnqualifiedName(localName); 255 } 256 257 public void setOmitXmlDecl(String value) { 258 this.omitXmlDecl = value; 259 } 260 261 public void setXmlDecl(String value) { 262 this.xmlDecl = value; 263 } 264 265 public void setCharsetEncoding(String value) { 266 charset = value; 267 } 268 269 @Override 270 public void output(OutputStream out) throws IOException { 271 try { 272// materializeBody(); 273 Transformer transformer = 274 EfficientStreamingTransformer.newTransformer(); 275 276 transformer.setOutputProperty( 277 OutputKeys.OMIT_XML_DECLARATION, "yes"); 278 /*omitXmlDecl);*/ 279 // no equivalent for "setExpandEmptyElements" 280 transformer.setOutputProperty( 281 OutputKeys.ENCODING, 282 charset); 283 284 if (omitXmlDecl.equals("no") && xmlDecl == null) { 285 xmlDecl = "<?xml version=\"" + getOwnerDocument().getXmlVersion() + "\" encoding=\"" + 286 charset + "\" ?>"; 287 } 288 289 StreamResult result = new StreamResult(out); 290 if (xmlDecl != null) { 291 OutputStreamWriter writer = new OutputStreamWriter(out, charset); 292 writer.write(xmlDecl); 293 writer.flush(); 294 result = new StreamResult(writer); 295 } 296 297 if (log.isLoggable(Level.FINE)) { 298 log.log(Level.FINE, "SAAJ0190.impl.set.xml.declaration", 299 new String[] { omitXmlDecl }); 300 log.log(Level.FINE, "SAAJ0191.impl.set.encoding", 301 new String[] { charset }); 302 } 303 304 //StreamResult result = new StreamResult(out); 305 transformer.transform(getContent(), result); 306 } catch (Exception ex) { 307 throw new IOException(ex.getMessage()); 308 } 309 } 310 311 /** 312 * Serialize to FI if boolean parameter set. 313 */ 314 @Override 315 public void output(OutputStream out, boolean isFastInfoset) 316 throws IOException 317 { 318 if (!isFastInfoset) { 319 output(out); 320 } 321 else { 322 try { 323 // Run transform and generate FI output from content 324 Transformer transformer = EfficientStreamingTransformer.newTransformer(); 325 transformer.transform(getContent(), 326 FastInfosetReflection.FastInfosetResult_new(out)); 327 } 328 catch (Exception ex) { 329 throw new IOException(ex.getMessage()); 330 } 331 } 332 } 333 334 // public void prettyPrint(OutputStream out) throws IOException { 335 // if (getDocument() == null) 336 // initDocument(); 337 // 338 // OutputFormat format = OutputFormat.createPrettyPrint(); 339 // 340 // format.setIndentSize(2); 341 // format.setNewlines(true); 342 // format.setTrimText(true); 343 // format.setPadText(true); 344 // format.setExpandEmptyElements(false); 345 // 346 // XMLWriter writer = new XMLWriter(out, format); 347 // writer.write(getDocument()); 348 // } 349 // 350 // public void prettyPrint(Writer out) throws IOException { 351 // if (getDocument() == null) 352 // initDocument(); 353 // 354 // OutputFormat format = OutputFormat.createPrettyPrint(); 355 // 356 // format.setIndentSize(2); 357 // format.setNewlines(true); 358 // format.setTrimText(true); 359 // format.setPadText(true); 360 // format.setExpandEmptyElements(false); 361 // 362 // XMLWriter writer = new XMLWriter(out, format); 363 // writer.write(getDocument()); 364 // } 365 366 367 @Override 368 public SOAPElement setElementQName(QName newName) throws SOAPException { 369 log.log(Level.SEVERE, 370 "SAAJ0146.impl.invalid.name.change.requested", 371 new Object[] {elementQName.getLocalPart(), 372 newName.getLocalPart()}); 373 throw new SOAPException("Cannot change name for " 374 + elementQName.getLocalPart() + " to " 375 + newName.getLocalPart()); 376 } 377 378 @Override 379 public void setStaxBridge(StaxBridge bridge) throws SOAPException { 380 //set it on the body 381 ((BodyImpl) getBody()).setStaxBridge(bridge); 382 } 383 384 @Override 385 public StaxBridge getStaxBridge() throws SOAPException { 386 return ((BodyImpl) getBody()).getStaxBridge(); 387 } 388 389 @Override 390 public XMLStreamReader getPayloadReader() throws SOAPException { 391 return ((BodyImpl) getBody()).getPayloadReader(); 392 } 393 394 @Override 395 public void writeTo(final XMLStreamWriter writer) throws XMLStreamException, SOAPException { 396 StaxBridge readBridge = this.getStaxBridge(); 397 if (readBridge != null && readBridge instanceof StaxLazySourceBridge) { 398// StaxSoapWriteBridge writingBridge = new StaxSoapWriteBridge(this); 399// writingBridge.write(writer); 400 final String soapEnvNS = this.getNamespaceURI(); 401 final DOMStreamReader reader = new DOMStreamReader(this); 402 XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); 403 writingBridge.bridge( new XMLStreamReaderToXMLStreamWriter.Breakpoint(reader, writer) { 404 @Override 405 public boolean proceedAfterStartElement() { 406 if ("Body".equals(reader.getLocalName()) && soapEnvNS.equals(reader.getNamespaceURI()) ){ 407 return false; 408 } else 409 return true; 410 } 411 });//bridgeToBodyStartTag 412 ((StaxLazySourceBridge)readBridge).writePayloadTo(writer); 413 writer.writeEndElement();//body 414 writer.writeEndElement();//env 415 writer.writeEndDocument(); 416 writer.flush(); 417 } else { 418 LazyEnvelopeStaxReader lazyEnvReader = new LazyEnvelopeStaxReader(this); 419 XMLStreamReaderToXMLStreamWriter writingBridge = new XMLStreamReaderToXMLStreamWriter(); 420 writingBridge.bridge(lazyEnvReader, writer); 421// writingBridge.bridge(new XMLStreamReaderToXMLStreamWriter.Breakpoint(lazyEnvReader, writer)); 422 } 423 //Assume the staxBridge is exhausted now since we would have read the body reader 424 ((BodyImpl) getBody()).setPayloadStreamRead(); 425 } 426 427 @Override 428 public QName getPayloadQName() throws SOAPException { 429 return ((BodyImpl) getBody()).getPayloadQName(); 430 } 431 432 @Override 433 public String getPayloadAttributeValue(String localName) throws SOAPException { 434 return ((BodyImpl) getBody()).getPayloadAttributeValue(localName); 435 } 436 437 @Override 438 public String getPayloadAttributeValue(QName qName) throws SOAPException { 439 return ((BodyImpl) getBody()).getPayloadAttributeValue(qName); 440 } 441 442 @Override 443 public boolean isLazy() { 444 try { 445 return ((BodyImpl) getBody()).isLazy(); 446 } catch (SOAPException e) { 447 return false; 448 } 449 } 450 451} 452