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.messaging.saaj.soap.impl; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.io.OutputStreamWriter; 31 32 import java.util.Iterator; 33 import java.util.logging.Level; 34 import org.w3c.dom.Document; 35 36 import javax.xml.namespace.QName; 37 import javax.xml.soap.*; 38 import javax.xml.transform.*; 39 import javax.xml.transform.dom.DOMSource; 40 import javax.xml.transform.stream.StreamResult; 41 import javax.xml.transform.sax.*; 42 43 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; 44 import com.sun.xml.internal.messaging.saaj.soap.Envelope; 45 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl; 46 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl; 47 import com.sun.xml.internal.messaging.saaj.util.FastInfosetReflection; 48 import com.sun.xml.internal.messaging.saaj.util.transform.EfficientStreamingTransformer; 49 50 /** 51 * Our implementation of the SOAP envelope. 52 * 53 * @author Anil Vijendran (anil@sun.com) 54 */ 55 public abstract class EnvelopeImpl extends ElementImpl implements Envelope { 56 protected HeaderImpl header; 57 protected BodyImpl body; 58 String omitXmlDecl = "yes"; 59 String charset = "utf-8"; 60 String xmlDecl = null; 61 62 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, Name name) { 63 super(ownerDoc, name); 64 } 65 66 protected EnvelopeImpl(SOAPDocumentImpl ownerDoc, QName name) { 67 super(ownerDoc, name); 68 } 69 70 protected EnvelopeImpl( 71 SOAPDocumentImpl ownerDoc, 72 NameImpl name, 73 boolean createHeader, 74 boolean createBody) 75 throws SOAPException { 76 this(ownerDoc, name); 77 78 ensureNamespaceIsDeclared( 79 getElementQName().getPrefix(), getElementQName().getNamespaceURI()); 80 81 // XXX 82 if (createHeader) 83 addHeader(); 84 85 if (createBody) 86 addBody(); 87 } 88 89 protected abstract NameImpl getHeaderName(String prefix); 90 protected abstract NameImpl getBodyName(String prefix); 91 92 public SOAPHeader addHeader() throws SOAPException { 93 return addHeader(null); 94 } 95 96 public SOAPHeader addHeader(String prefix) throws SOAPException { 97 98 if (prefix == null || prefix.equals("")) { 99 prefix = getPrefix(); 100 } 101 102 NameImpl headerName = getHeaderName(prefix); 103 NameImpl bodyName = getBodyName(prefix); 104 105 HeaderImpl header = null; 106 SOAPElement firstChild = null; 107 108 Iterator eachChild = getChildElementNodes(); 109 if (eachChild.hasNext()) { 110 firstChild = (SOAPElement) eachChild.next(); 111 if (firstChild.getElementName().equals(headerName)) { 112 log.severe("SAAJ0120.impl.header.already.exists"); 113 throw new SOAPExceptionImpl("Can't add a header when one is already present."); 114 } else if (!firstChild.getElementName().equals(bodyName)) { 115 log.severe("SAAJ0121.impl.invalid.first.child.of.envelope"); 116 throw new SOAPExceptionImpl("First child of Envelope must be either a Header or Body"); 117 } 118 } 119 120 header = (HeaderImpl) createElement(headerName); 121 insertBefore(header, firstChild); 122 header.ensureNamespaceIsDeclared(headerName.getPrefix(), headerName.getURI()); 123 124 return header; 125 } 126 127 protected void lookForHeader() throws SOAPException { 128 NameImpl headerName = getHeaderName(null); 129 130 HeaderImpl hdr = (HeaderImpl) findChild(headerName); 131 header = hdr; 132 } 133 134 public SOAPHeader getHeader() throws SOAPException { 135 lookForHeader(); 136 return header; 137 } 138 139 protected void lookForBody() throws SOAPException { 140 NameImpl bodyName = getBodyName(null); 141 142 BodyImpl bodyChildElement = (BodyImpl) findChild(bodyName); 143 body = bodyChildElement; 144 } 145 146 public SOAPBody addBody() throws SOAPException { 147 return addBody(null); 148 } 149 150 public SOAPBody addBody(String prefix) throws SOAPException { 151 lookForBody(); 152 153 if (prefix == null || prefix.equals("")) { 154 prefix = getPrefix(); 155 } 156 157 if (body == null) { 158 NameImpl bodyName = getBodyName(prefix); 159 body = (BodyImpl) createElement(bodyName); 160 insertBefore(body, null); 161 body.ensureNamespaceIsDeclared(bodyName.getPrefix(), bodyName.getURI()); 162 } else { 163 log.severe("SAAJ0122.impl.body.already.exists"); 164 throw new SOAPExceptionImpl("Can't add a body when one is already present."); 165 } 166 167 return body; 168 } 169 170 protected SOAPElement addElement(Name name) throws SOAPException { 171 if (getBodyName(null).equals(name)) { 172 return addBody(name.getPrefix()); 173 } 174 if (getHeaderName(null).equals(name)) { 175 return addHeader(name.getPrefix()); 176 } 177 178 return super.addElement(name); 179 } 180 181 protected SOAPElement addElement(QName name) throws SOAPException { 182 if (getBodyName(null).equals(NameImpl.convertToName(name))) { 183 return addBody(name.getPrefix()); 184 } 185 if (getHeaderName(null).equals(NameImpl.convertToName(name))) { 186 return addHeader(name.getPrefix()); 187 } 188 189 return super.addElement(name); 190 } 191 192 public SOAPBody getBody() throws SOAPException { 193 lookForBody(); 194 return body; 195 } 196 197 public Source getContent() { 198 return new DOMSource(getOwnerDocument()); 199 } 200 201 public Name createName(String localName, String prefix, String uri) 202 throws SOAPException { 203 204 // validating parameters before passing them on 205 // to make sure that the namespace specification rules are followed 206 207 // reserved xmlns prefix cannot be used. 208 if ("xmlns".equals(prefix)) { 209 log.severe("SAAJ0123.impl.no.reserved.xmlns"); 210 throw new SOAPExceptionImpl("Cannot declare reserved xmlns prefix"); 211 } 212 // Qualified name cannot be xmlns. 213 if ((prefix == null) && ("xmlns".equals(localName))) { 214 log.severe("SAAJ0124.impl.qualified.name.cannot.be.xmlns"); 215 throw new SOAPExceptionImpl("Qualified name cannot be xmlns"); 216 } 217 218 return NameImpl.create(localName, prefix, uri); 219 } 220 221 public Name createName(String localName, String prefix) 222 throws SOAPException { 223 String namespace = getNamespaceURI(prefix); 224 if (namespace == null) { 225 log.log( 226 Level.SEVERE, 227 "SAAJ0126.impl.cannot.locate.ns", 228 new String[] { prefix }); 229 throw new SOAPExceptionImpl( 230 "Unable to locate namespace for prefix " + prefix); 231 } 232 return NameImpl.create(localName, prefix, namespace); 233 } 234 235 public Name createName(String localName) throws SOAPException { 236 return NameImpl.createFromUnqualifiedName(localName); 237 } 238 239 public void setOmitXmlDecl(String value) { 240 this.omitXmlDecl = value; 241 } 242 243 public void setXmlDecl(String value) { 244 this.xmlDecl = value; 245 } 246 247 private String getOmitXmlDecl() { 248 return this.omitXmlDecl; 249 } 250 251 public void setCharsetEncoding(String value) { 252 charset = value; 253 } 254 255 public void output(OutputStream out) throws IOException { 256 try { 257 Transformer transformer = 258 EfficientStreamingTransformer.newTransformer(); 259 260 transformer.setOutputProperty( 261 OutputKeys.OMIT_XML_DECLARATION, "yes"); 262 /*omitXmlDecl);*/ 263 // no equivalent for "setExpandEmptyElements" 264 transformer.setOutputProperty( 265 OutputKeys.ENCODING, 266 charset); 267 268 if (omitXmlDecl.equals("no") && xmlDecl == null) { 269 xmlDecl = "<?xml version=\"" + getOwnerDocument().getXmlVersion() + "\" encoding=\"" + 270 charset + "\" ?>"; 271 } 272 273 StreamResult result = new StreamResult(out); 274 if (xmlDecl != null) { 275 OutputStreamWriter writer = new OutputStreamWriter(out, charset); 276 writer.write(xmlDecl); 277 writer.flush(); 278 result = new StreamResult(writer); 279 } 280 281 if (log.isLoggable(Level.FINE)) { 282 log.log(Level.FINE, "SAAJ0190.impl.set.xml.declaration", 283 new String[] { omitXmlDecl }); 284 log.log(Level.FINE, "SAAJ0191.impl.set.encoding", 285 new String[] { charset }); 286 } 287 288 //StreamResult result = new StreamResult(out); 289 transformer.transform(getContent(), result); 290 } catch (Exception ex) { 291 throw new IOException(ex.getMessage()); 292 } 293 } 294 295 /** 296 * Serialize to FI if boolean parameter set. 297 */ 298 public void output(OutputStream out, boolean isFastInfoset) 299 throws IOException 300 { 301 if (!isFastInfoset) { 302 output(out); 303 } 304 else { 305 try { 306 // Run transform and generate FI output from content 307 Source source = getContent(); 308 Transformer transformer = EfficientStreamingTransformer.newTransformer(); 309 transformer.transform(getContent(), 310 FastInfosetReflection.FastInfosetResult_new(out)); 311 } 312 catch (Exception ex) { 313 throw new IOException(ex.getMessage()); 314 } 315 } 316 } 317 318 // public void prettyPrint(OutputStream out) throws IOException { 319 // if (getDocument() == null) 320 // initDocument(); 321 // 322 // OutputFormat format = OutputFormat.createPrettyPrint(); 323 // 324 // format.setIndentSize(2); 325 // format.setNewlines(true); 326 // format.setTrimText(true); 327 // format.setPadText(true); 328 // format.setExpandEmptyElements(false); 329 // 330 // XMLWriter writer = new XMLWriter(out, format); 331 // writer.write(getDocument()); 332 // } 333 // 334 // public void prettyPrint(Writer 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 351 public SOAPElement setElementQName(QName newName) throws SOAPException { 352 log.log(Level.SEVERE, 353 "SAAJ0146.impl.invalid.name.change.requested", 354 new Object[] {elementQName.getLocalPart(), 355 newName.getLocalPart()}); 356 throw new SOAPException("Cannot change name for " 357 + elementQName.getLocalPart() + " to " 358 + newName.getLocalPart()); 359 } 360 }