1 /*
   2  * Copyright (c) 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.org.jvnet.staxex.util;
  27 
  28 import java.util.Arrays;
  29 import java.util.Iterator;
  30 
  31 import javax.xml.namespace.NamespaceContext;
  32 import javax.xml.namespace.QName;
  33 import javax.xml.soap.SOAPElement;
  34 import javax.xml.soap.SOAPException;
  35 import javax.xml.soap.SOAPMessage;
  36 import javax.xml.stream.XMLStreamException;
  37 import javax.xml.stream.XMLStreamWriter;
  38 
  39 import org.w3c.dom.Comment;
  40 import org.w3c.dom.Node;
  41 
  42 /**
  43  * SaajStaxWriter builds a SAAJ SOAPMessage by using XMLStreamWriter interface.
  44  *
  45  * @author shih-chang.chen@oracle.com
  46  */
  47 public class SaajStaxWriter implements XMLStreamWriter {
  48 
  49     protected SOAPMessage soap;
  50     protected String envURI;
  51     protected SOAPElement currentElement;
  52 
  53     static final protected String Envelope = "Envelope";
  54     static final protected String Header = "Header";
  55     static final protected String Body = "Body";
  56     static final protected String xmlns = "xmlns";
  57 
  58     public SaajStaxWriter(final SOAPMessage msg, String uri) throws SOAPException {
  59         soap = msg;
  60         this.envURI = uri;
  61     }
  62 
  63     public SOAPMessage getSOAPMessage() {
  64         return soap;
  65     }
  66 
  67     protected SOAPElement getEnvelope() throws SOAPException {
  68         return soap.getSOAPPart().getEnvelope();
  69     }
  70 
  71     @Override
  72     public void writeStartElement(final String localName) throws XMLStreamException {
  73         try {
  74             currentElement = currentElement.addChildElement(localName);
  75         } catch (SOAPException e) {
  76             throw new XMLStreamException(e);
  77         }
  78     }
  79 
  80     @Override
  81     public void writeStartElement(final String ns, final String ln) throws XMLStreamException {
  82         writeStartElement(null, ln, ns);
  83     }
  84 
  85     @Override
  86     public void writeStartElement(final String prefix, final String ln, final String ns) throws XMLStreamException {
  87         try {
  88             if (envURI.equals(ns)) {
  89                 if (Envelope.equals(ln)) {
  90                     currentElement = getEnvelope();
  91                     fixPrefix(prefix);
  92                     return;
  93                 } else if (Header.equals(ln)) {
  94                     currentElement = soap.getSOAPHeader();
  95                     fixPrefix(prefix);
  96                     return;
  97                 } else if (Body.equals(ln)) {
  98                     currentElement = soap.getSOAPBody();
  99                     fixPrefix(prefix);
 100                     return;
 101                 }
 102             }
 103             currentElement = (prefix == null) ?
 104                     currentElement.addChildElement(new QName(ns, ln)) :
 105                     currentElement.addChildElement(ln, prefix, ns);
 106         } catch (SOAPException e) {
 107             throw new XMLStreamException(e);
 108         }
 109     }
 110 
 111     private void fixPrefix(final String prfx) throws XMLStreamException {
 112         String oldPrfx = currentElement.getPrefix();
 113         if (prfx != null && !prfx.equals(oldPrfx)) {
 114             currentElement.setPrefix(prfx);
 115         }
 116     }
 117 
 118     @Override
 119     public void writeEmptyElement(final String uri, final String ln) throws XMLStreamException {
 120         writeStartElement(null, ln, uri);
 121     }
 122 
 123     @Override
 124     public void writeEmptyElement(final String prefix, final String ln, final String uri) throws XMLStreamException {
 125         writeStartElement(prefix, ln, uri);
 126     }
 127 
 128     @Override
 129     public void writeEmptyElement(final String ln) throws XMLStreamException {
 130         writeStartElement(null, ln, null);
 131     }
 132 
 133     @Override
 134     public void writeEndElement() throws XMLStreamException {
 135         if (currentElement != null) currentElement = currentElement.getParentElement();
 136     }
 137 
 138     @Override
 139     public void writeEndDocument() throws XMLStreamException {
 140     }
 141 
 142     @Override
 143     public void close() throws XMLStreamException {
 144     }
 145 
 146     @Override
 147     public void flush() throws XMLStreamException {
 148     }
 149 
 150     @Override
 151     public void writeAttribute(final String ln, final String val) throws XMLStreamException {
 152         writeAttribute(null, null, ln, val);
 153     }
 154 
 155     @Override
 156     public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException {
 157         try {
 158             if (ns == null) {
 159                 if (prefix == null && xmlns.equals(ln)) {
 160                     currentElement.addNamespaceDeclaration("", value);
 161                 } else {
 162                     currentElement.setAttributeNS("", ln, value);
 163                 }
 164             } else {
 165                 QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix);
 166                 currentElement.addAttribute(name, value);
 167             }
 168         } catch (SOAPException e) {
 169             throw new XMLStreamException(e);
 170         }
 171     }
 172 
 173     @Override
 174     public void writeAttribute(final String ns, final String ln, final String val) throws XMLStreamException {
 175         writeAttribute(null, ns, ln, val);
 176     }
 177 
 178     @Override
 179     public void writeNamespace(String prefix, final String uri) throws XMLStreamException {
 180 
 181         // make prefix default if null or "xmlns" (according to javadoc)
 182         if (prefix == null || "xmlns".equals(prefix)) {
 183             prefix = "";
 184         }
 185 
 186         try {
 187             currentElement.addNamespaceDeclaration(prefix, uri);
 188         } catch (SOAPException e) {
 189             throw new XMLStreamException(e);
 190         }
 191     }
 192 
 193     @Override
 194     public void writeDefaultNamespace(final String uri) throws XMLStreamException {
 195         writeNamespace("", uri);
 196     }
 197 
 198     @Override
 199     public void writeComment(final String data) throws XMLStreamException {
 200         Comment c = soap.getSOAPPart().createComment(data);
 201         currentElement.appendChild(c);
 202     }
 203 
 204     @Override
 205     public void writeProcessingInstruction(final String target) throws XMLStreamException {
 206         Node n = soap.getSOAPPart().createProcessingInstruction(target, "");
 207         currentElement.appendChild(n);
 208     }
 209 
 210     @Override
 211     public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
 212         Node n = soap.getSOAPPart().createProcessingInstruction(target, data);
 213         currentElement.appendChild(n);
 214     }
 215 
 216     @Override
 217     public void writeCData(final String data) throws XMLStreamException {
 218         Node n = soap.getSOAPPart().createCDATASection(data);
 219         currentElement.appendChild(n);
 220     }
 221 
 222     @Override
 223     public void writeDTD(final String dtd) throws XMLStreamException {
 224         //TODO ... Don't do anything here
 225     }
 226 
 227     @Override
 228     public void writeEntityRef(final String name) throws XMLStreamException {
 229         Node n = soap.getSOAPPart().createEntityReference(name);
 230         currentElement.appendChild(n);
 231     }
 232 
 233     @Override
 234     public void writeStartDocument() throws XMLStreamException {
 235     }
 236 
 237     @Override
 238     public void writeStartDocument(final String version) throws XMLStreamException {
 239         if (version != null) soap.getSOAPPart().setXmlVersion(version);
 240     }
 241 
 242     @Override
 243     public void writeStartDocument(final String encoding, final String version) throws XMLStreamException {
 244         if (version != null) soap.getSOAPPart().setXmlVersion(version);
 245         if (encoding != null) {
 246             try {
 247                 soap.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
 248             } catch (SOAPException e) {
 249                 throw new XMLStreamException(e);
 250             }
 251         }
 252     }
 253 
 254     @Override
 255     public void writeCharacters(final String text) throws XMLStreamException {
 256         try {
 257             currentElement.addTextNode(text);
 258         } catch (SOAPException e) {
 259             throw new XMLStreamException(e);
 260         }
 261     }
 262 
 263     @Override
 264     public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
 265         char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len);
 266         try {
 267             currentElement.addTextNode(new String(chr));
 268         } catch (SOAPException e) {
 269             throw new XMLStreamException(e);
 270         }
 271     }
 272 
 273     @Override
 274     public String getPrefix(final String uri) throws XMLStreamException {
 275         return currentElement.lookupPrefix(uri);
 276     }
 277 
 278     @Override
 279     public void setPrefix(final String prefix, final String uri) throws XMLStreamException {
 280         try {
 281             this.currentElement.addNamespaceDeclaration(prefix, uri);
 282         } catch (SOAPException e) {
 283             throw new XMLStreamException(e);
 284         }
 285     }
 286 
 287     @Override
 288     public void setDefaultNamespace(final String uri) throws XMLStreamException {
 289         setPrefix("", uri);
 290     }
 291 
 292     @Override
 293     public void setNamespaceContext(final NamespaceContext context)throws XMLStreamException {
 294         throw new UnsupportedOperationException();
 295     }
 296 
 297     @Override
 298     public Object getProperty(final String name) throws IllegalArgumentException {
 299         //TODO the following line is to make eclipselink happy ... they are aware of this problem -
 300         if (javax.xml.stream.XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name)) return Boolean.FALSE;
 301         return null;
 302     }
 303 
 304     @Override
 305     public NamespaceContext getNamespaceContext() {
 306         return new NamespaceContext() {
 307             public String getNamespaceURI(final String prefix) {
 308                 return currentElement.getNamespaceURI(prefix);
 309             }
 310             public String getPrefix(final String namespaceURI) {
 311                 return currentElement.lookupPrefix(namespaceURI);
 312             }
 313             public Iterator getPrefixes(final String namespaceURI) {
 314                 return new Iterator() {
 315                     String prefix = getPrefix(namespaceURI);
 316                     public boolean hasNext() {
 317                         return (prefix != null);
 318                     }
 319                     public Object next() {
 320                         if (!hasNext()) throw new java.util.NoSuchElementException();
 321                         String next = prefix;
 322                         prefix = null;
 323                         return next;
 324                     }
 325                     public void remove() {}
 326                 };
 327             }
 328         };
 329     }
 330 }