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 26 package com.sun.xml.internal.messaging.saaj.soap.impl; 27 28 import java.util.Iterator; 29 import java.util.Locale; 30 import java.util.logging.Level; 31 32 import javax.xml.namespace.QName; 33 import javax.xml.soap.*; 34 import javax.xml.stream.XMLStreamException; 35 import javax.xml.stream.XMLStreamReader; 36 import javax.xml.parsers.DocumentBuilder; 37 import javax.xml.parsers.DocumentBuilderFactory; 38 39 import org.w3c.dom.*; 40 import org.w3c.dom.Node; 41 42 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; 43 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument; 44 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; 45 import com.sun.xml.internal.messaging.saaj.soap.StaxBridge; 46 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; 47 48 /** 49 * The implementation of SOAP-ENV:BODY or the SOAPBody abstraction. 50 * 51 * @author Anil Vijendran (anil@sun.com) 52 */ 53 public abstract class BodyImpl extends ElementImpl implements SOAPBody { 54 private SOAPFault fault; 55 // private XMLStreamReaderToXMLStreamWriter staxBridge; 56 private StaxBridge staxBridge; 57 private boolean payloadStreamRead = false; 58 59 protected BodyImpl(SOAPDocumentImpl ownerDoc, NameImpl bodyName) { 60 super(ownerDoc, bodyName); 61 } 62 63 protected abstract NameImpl getFaultName(String name); 64 protected abstract boolean isFault(SOAPElement child); 65 protected abstract SOAPBodyElement createBodyElement(Name name); 66 protected abstract SOAPBodyElement createBodyElement(QName name); 67 protected abstract SOAPFault createFaultElement(); 68 protected abstract QName getDefaultFaultCode(); 69 70 public SOAPFault addFault() throws SOAPException { 71 if (hasFault()) { 72 log.severe("SAAJ0110.impl.fault.already.exists"); 73 throw new SOAPExceptionImpl("Error: Fault already exists"); 74 } 75 76 fault = createFaultElement(); 77 78 addNode(fault); 79 80 fault.setFaultCode(getDefaultFaultCode()); 81 fault.setFaultString("Fault string, and possibly fault code, not set"); 82 83 return fault; 84 } 85 86 public SOAPFault addFault( 87 Name faultCode, 88 String faultString, 89 Locale locale) 90 throws SOAPException { 91 92 SOAPFault fault = addFault(); 93 fault.setFaultCode(faultCode); 94 fault.setFaultString(faultString, locale); 95 return fault; 96 } 97 98 public SOAPFault addFault( 99 QName faultCode, 100 String faultString, 101 Locale locale) 102 throws SOAPException { 103 104 SOAPFault fault = addFault(); 105 fault.setFaultCode(faultCode); 106 fault.setFaultString(faultString, locale); 107 return fault; 108 } 109 110 public SOAPFault addFault(Name faultCode, String faultString) 111 throws SOAPException { 112 113 SOAPFault fault = addFault(); 114 fault.setFaultCode(faultCode); 115 fault.setFaultString(faultString); 116 return fault; 117 } 118 119 public SOAPFault addFault(QName faultCode, String faultString) 120 throws SOAPException { 121 122 SOAPFault fault = addFault(); 123 fault.setFaultCode(faultCode); 124 fault.setFaultString(faultString); 125 return fault; 126 } 127 128 void initializeFault() { 129 FaultImpl flt = (FaultImpl) findFault(); 130 fault = flt; 131 } 132 133 protected SOAPElement findFault() { 134 Iterator eachChild = getChildElementNodes(); 135 while (eachChild.hasNext()) { 136 SOAPElement child = (SOAPElement) eachChild.next(); 137 if (isFault(child)) { 138 return child; 139 } 140 } 141 142 return null; 143 } 144 145 public boolean hasFault() { 146 QName payloadQName = getPayloadQName(); 147 return getFaultQName().equals(payloadQName); 148 } 149 150 private Object getFaultQName() { 151 return new QName(getNamespaceURI(), "Fault"); 152 } 153 154 public SOAPFault getFault() { 155 if (hasFault()) { 156 if (fault == null) { 157 //initialize fault member 158 fault = (SOAPFault) getFirstChildElement(); 159 } 160 return fault; 161 } 162 return null; 163 } 164 165 public SOAPBodyElement addBodyElement(Name name) throws SOAPException { 166 SOAPBodyElement newBodyElement = 167 (SOAPBodyElement) ElementFactory.createNamedElement( 168 ((SOAPDocument) getOwnerDocument()).getDocument(), 169 name.getLocalName(), 170 name.getPrefix(), 171 name.getURI()); 172 if (newBodyElement == null) { 173 newBodyElement = createBodyElement(name); 174 } 175 addNode(newBodyElement); 176 return newBodyElement; 177 } 178 179 public SOAPBodyElement addBodyElement(QName qname) throws SOAPException { 180 SOAPBodyElement newBodyElement = 181 (SOAPBodyElement) ElementFactory.createNamedElement( 182 ((SOAPDocument) getOwnerDocument()).getDocument(), 183 qname.getLocalPart(), 184 qname.getPrefix(), 185 qname.getNamespaceURI()); 186 if (newBodyElement == null) { 187 newBodyElement = createBodyElement(qname); 188 } 189 addNode(newBodyElement); 190 return newBodyElement; 191 } 192 193 public void setParentElement(SOAPElement element) throws SOAPException { 194 195 if (!(element instanceof SOAPEnvelope)) { 196 log.severe("SAAJ0111.impl.body.parent.must.be.envelope"); 197 throw new SOAPException("Parent of SOAPBody has to be a SOAPEnvelope"); 198 } 199 super.setParentElement(element); 200 } 201 202 protected SOAPElement addElement(Name name) throws SOAPException { 203 return addBodyElement(name); 204 } 205 206 protected SOAPElement addElement(QName name) throws SOAPException { 207 return addBodyElement(name); 208 } 209 210 // public Node insertBefore(Node newElement, Node ref) throws DOMException { 211 // if (!(newElement instanceof SOAPBodyElement) && (newElement instanceof SOAPElement)) { 212 // newElement = new ElementWrapper((ElementImpl) newElement); 213 // } 214 // return super.insertBefore(newElement, ref); 215 // } 216 // 217 // public Node replaceChild(Node newElement, Node ref) throws DOMException { 218 // if (!(newElement instanceof SOAPBodyElement) && (newElement instanceof SOAPElement)) { 219 // newElement = new ElementWrapper((ElementImpl) newElement); 220 // } 221 // return super.replaceChild(newElement, ref); 222 // } 223 224 public SOAPBodyElement addDocument(Document document) 225 throws SOAPException { 226 /* 227 228 Element rootNode = 229 document.getDocumentElement(); 230 // Causes all deferred nodes to be inflated 231 rootNode.normalize(); 232 adoptElement(rootNode); 233 SOAPBodyElement bodyElement = (SOAPBodyElement) convertToSoapElement(rootNode); 234 addNode(bodyElement); 235 return bodyElement; 236 */ 237 ///* 238 SOAPBodyElement newBodyElement = null; 239 DocumentFragment docFrag = document.createDocumentFragment(); 240 Element rootElement = document.getDocumentElement(); 241 if(rootElement != null) { 242 docFrag.appendChild(rootElement); 243 244 Document ownerDoc = getOwnerDocument(); 245 // This copies the whole tree which could be very big so it's slow. 246 // However, it does have the advantage of actually working. 247 org.w3c.dom.Node replacingNode = ownerDoc.importNode(docFrag, true); 248 // Adding replacingNode at the last of the children list of body 249 addNode(replacingNode); 250 Iterator i = 251 getChildElements(NameImpl.copyElementName(rootElement)); 252 // Return the child element with the required name which is at the 253 // end of the list 254 while(i.hasNext()) 255 newBodyElement = (SOAPBodyElement) i.next(); 256 } 257 return newBodyElement; 258 //*/ 259 } 260 261 protected SOAPElement convertToSoapElement(Element element) { 262 if ((element instanceof SOAPBodyElement) && 263 //this check is required because ElementImpl currently 264 // implements SOAPBodyElement 265 !(element.getClass().equals(ElementImpl.class))) { 266 return (SOAPElement) element; 267 } else { 268 return replaceElementWithSOAPElement( 269 element, 270 (ElementImpl) createBodyElement(NameImpl 271 .copyElementName(element))); 272 } 273 } 274 275 public SOAPElement setElementQName(QName newName) throws SOAPException { 276 log.log(Level.SEVERE, 277 "SAAJ0146.impl.invalid.name.change.requested", 278 new Object[] {elementQName.getLocalPart(), 279 newName.getLocalPart()}); 280 throw new SOAPException("Cannot change name for " 281 + elementQName.getLocalPart() + " to " 282 + newName.getLocalPart()); 283 } 284 285 public Document extractContentAsDocument() throws SOAPException { 286 287 Iterator eachChild = getChildElements(); 288 javax.xml.soap.Node firstBodyElement = null; 289 290 while (eachChild.hasNext() && 291 !(firstBodyElement instanceof SOAPElement)) 292 firstBodyElement = (javax.xml.soap.Node) eachChild.next(); 293 294 boolean exactlyOneChildElement = true; 295 if (firstBodyElement == null) 296 exactlyOneChildElement = false; 297 else { 298 for (org.w3c.dom.Node node = firstBodyElement.getNextSibling(); 299 node != null; 300 node = node.getNextSibling()) { 301 302 if (node instanceof Element) { 303 exactlyOneChildElement = false; 304 break; 305 } 306 } 307 } 308 309 if(!exactlyOneChildElement) { 310 log.log(Level.SEVERE, 311 "SAAJ0250.impl.body.should.have.exactly.one.child"); 312 throw new SOAPException("Cannot extract Document from body"); 313 } 314 315 Document document = null; 316 try { 317 DocumentBuilderFactory factory = 318 new com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl(); 319 factory.setNamespaceAware(true); 320 DocumentBuilder builder = factory.newDocumentBuilder(); 321 document = builder.newDocument(); 322 323 Element rootElement = (Element) document.importNode( 324 firstBodyElement, 325 true); 326 327 document.appendChild(rootElement); 328 329 } catch(Exception e) { 330 log.log(Level.SEVERE, 331 "SAAJ0251.impl.cannot.extract.document.from.body"); 332 throw new SOAPExceptionImpl( 333 "Unable to extract Document from body", e); 334 } 335 336 firstBodyElement.detachNode(); 337 338 return document; 339 } 340 341 private void materializePayloadWrapException() { 342 try { 343 materializePayload(); 344 } catch (SOAPException e) { 345 throw new RuntimeException(e); 346 } 347 } 348 private void materializePayload() throws SOAPException { 349 if (staxBridge != null) { 350 if (payloadStreamRead) { 351 //the payload has already been read via stream reader and the 352 //stream has been exhausted already. Throw an 353 //exception since we are now trying to materialize as DOM and 354 //there is no stream left to read 355 throw new SOAPException("SOAPBody payload stream has been fully read - cannot materialize as DOM!"); 356 } 357 try { 358 staxBridge.bridgePayload(); 359 staxBridge = null; 360 payloadStreamRead = true; 361 } catch (XMLStreamException e) { 362 throw new SOAPException(e); 363 } 364 } 365 } 366 367 @Override 368 public boolean hasChildNodes() { 369 boolean hasChildren = super.hasChildNodes(); 370 //to answer this question we need to know _whether_ we have at least one child 371 //So no need to materialize body if we already know we have a header child 372 if (!hasChildren) { 373 materializePayloadWrapException(); 374 } 375 return super.hasChildNodes(); 376 } 377 378 @Override 379 public NodeList getChildNodes() { 380 materializePayloadWrapException(); 381 return super.getChildNodes(); 382 } 383 384 @Override 385 public Node getFirstChild() { 386 Node child = super.getFirstChild(); 387 if (child == null) { 388 materializePayloadWrapException(); 389 } 390 return super.getFirstChild(); 391 } 392 393 public Node getFirstChildNoMaterialize() { 394 return super.getFirstChild(); 395 } 396 397 @Override 398 public Node getLastChild() { 399 materializePayloadWrapException(); 400 return super.getLastChild(); 401 } 402 403 XMLStreamReader getPayloadReader() { 404 return staxBridge.getPayloadReader(); 405 } 406 407 void setStaxBridge(StaxBridge bridge) { 408 this.staxBridge = bridge; 409 } 410 411 StaxBridge getStaxBridge() { 412 return staxBridge; 413 } 414 415 void setPayloadStreamRead() { 416 this.payloadStreamRead = true; 417 } 418 419 QName getPayloadQName() { 420 if (staxBridge != null) { 421 return staxBridge.getPayloadQName(); 422 } else { 423 //not lazy - Just get first child element and return its name 424 Element elem = getFirstChildElement(); 425 if (elem != null) { 426 String ns = elem.getNamespaceURI(); 427 String pref = elem.getPrefix(); 428 String local = elem.getLocalName(); 429 if (pref != null) return new QName(ns, local, pref); 430 if (ns != null) return new QName(ns, local); 431 return new QName(local); 432 } 433 } 434 return null; 435 } 436 437 String getPayloadAttributeValue(String attName) { 438 if (staxBridge != null) { 439 return staxBridge.getPayloadAttributeValue(attName); 440 } else { 441 //not lazy -Just get first child element and return its attribute 442 Element elem = getFirstChildElement(); 443 if (elem != null) { 444 return elem.getAttribute(localName); 445 } 446 } 447 return null; 448 } 449 450 String getPayloadAttributeValue(QName attNAme) { 451 if (staxBridge != null) { 452 return staxBridge.getPayloadAttributeValue(attNAme); 453 } else { 454 //not lazy -Just get first child element and return its attribute 455 Element elem = getFirstChildElement(); 456 if (elem != null) { 457 return elem.getAttributeNS(attNAme.getNamespaceURI(), attNAme.getLocalPart()); 458 } 459 } 460 return null; 461 } 462 463 public boolean isLazy() { 464 return (staxBridge != null && !payloadStreamRead); 465 } 466 467 }