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.messaging.saaj.util.stax;
  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         fixPrefix(prfx, currentElement);
 113     }
 114 
 115     private void fixPrefix(final String prfx, SOAPElement element) throws XMLStreamException {
 116         String oldPrfx = element.getPrefix();
 117         if (prfx != null && !prfx.equals(oldPrfx)) {
 118             element.setPrefix(prfx);
 119         }
 120     }
 121 
 122     @Override
 123     public void writeEmptyElement(final String uri, final String ln) throws XMLStreamException {
 124         writeStartElement(null, ln, uri);
 125     }
 126 
 127     @Override
 128     public void writeEmptyElement(final String prefix, final String ln, final String uri) throws XMLStreamException {
 129         writeStartElement(prefix, ln, uri);
 130     }
 131 
 132     @Override
 133     public void writeEmptyElement(final String ln) throws XMLStreamException {
 134         writeStartElement(null, ln, null);
 135     }
 136 
 137     @Override
 138     public void writeEndElement() throws XMLStreamException {
 139         if (currentElement != null) currentElement = currentElement.getParentElement();
 140     }
 141 
 142     @Override
 143     public void writeEndDocument() throws XMLStreamException {
 144     }
 145 
 146     @Override
 147     public void close() throws XMLStreamException {
 148     }
 149 
 150     @Override
 151     public void flush() throws XMLStreamException {
 152     }
 153 
 154     @Override
 155     public void writeAttribute(final String ln, final String val) throws XMLStreamException {
 156         writeAttribute(null, null, ln, val);
 157     }
 158 
 159     @Override
 160     public void writeAttribute(final String prefix, final String ns, final String ln, final String value) throws XMLStreamException {
 161         try {
 162             if (ns == null) {
 163                 if (prefix == null && xmlns.equals(ln)) {
 164                     currentElement.addNamespaceDeclaration("", value);
 165                 } else {
 166                     currentElement.setAttributeNS("", ln, value);
 167                 }
 168             } else {
 169                 QName name = (prefix == null) ? new QName(ns, ln) : new QName(ns, ln, prefix);
 170                 currentElement.addAttribute(name, value);
 171             }
 172         } catch (SOAPException e) {
 173             throw new XMLStreamException(e);
 174         }
 175     }
 176 
 177     @Override
 178     public void writeAttribute(final String ns, final String ln, final String val) throws XMLStreamException {
 179         writeAttribute(null, ns, ln, val);
 180     }
 181 
 182     @Override
 183     public void writeNamespace(String prefix, final String uri) throws XMLStreamException {
 184 
 185         // make prefix default if null or "xmlns" (according to javadoc)
 186         if (prefix == null || "xmlns".equals(prefix)) {
 187             prefix = "";
 188         }
 189 
 190         try {
 191             currentElement.addNamespaceDeclaration(prefix, uri);
 192         } catch (SOAPException e) {
 193             throw new XMLStreamException(e);
 194         }
 195     }
 196 
 197     @Override
 198     public void writeDefaultNamespace(final String uri) throws XMLStreamException {
 199         writeNamespace("", uri);
 200     }
 201 
 202     @Override
 203     public void writeComment(final String data) throws XMLStreamException {
 204         Comment c = soap.getSOAPPart().createComment(data);
 205         currentElement.appendChild(c);
 206     }
 207 
 208     @Override
 209     public void writeProcessingInstruction(final String target) throws XMLStreamException {
 210         Node n = soap.getSOAPPart().createProcessingInstruction(target, "");
 211         currentElement.appendChild(n);
 212     }
 213 
 214     @Override
 215     public void writeProcessingInstruction(final String target, final String data) throws XMLStreamException {
 216         Node n = soap.getSOAPPart().createProcessingInstruction(target, data);
 217         currentElement.appendChild(n);
 218     }
 219 
 220     @Override
 221     public void writeCData(final String data) throws XMLStreamException {
 222         Node n = soap.getSOAPPart().createCDATASection(data);
 223         currentElement.appendChild(n);
 224     }
 225 
 226     @Override
 227     public void writeDTD(final String dtd) throws XMLStreamException {
 228         //TODO ... Don't do anything here
 229     }
 230 
 231     @Override
 232     public void writeEntityRef(final String name) throws XMLStreamException {
 233         Node n = soap.getSOAPPart().createEntityReference(name);
 234         currentElement.appendChild(n);
 235     }
 236 
 237     @Override
 238     public void writeStartDocument() throws XMLStreamException {
 239     }
 240 
 241     @Override
 242     public void writeStartDocument(final String version) throws XMLStreamException {
 243         if (version != null) soap.getSOAPPart().setXmlVersion(version);
 244     }
 245 
 246     @Override
 247     public void writeStartDocument(final String encoding, final String version) throws XMLStreamException {
 248         if (version != null) soap.getSOAPPart().setXmlVersion(version);
 249         if (encoding != null) {
 250             try {
 251                 soap.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
 252             } catch (SOAPException e) {
 253                 throw new XMLStreamException(e);
 254             }
 255         }
 256     }
 257 
 258     @Override
 259     public void writeCharacters(final String text) throws XMLStreamException {
 260         try {
 261             currentElement.addTextNode(text);
 262         } catch (SOAPException e) {
 263             throw new XMLStreamException(e);
 264         }
 265     }
 266 
 267     @Override
 268     public void writeCharacters(final char[] text, final int start, final int len) throws XMLStreamException {
 269         char[] chr = (start == 0 && len == text.length) ? text : Arrays.copyOfRange(text, start, start + len);
 270         try {
 271             currentElement.addTextNode(new String(chr));
 272         } catch (SOAPException e) {
 273             throw new XMLStreamException(e);
 274         }
 275     }
 276 
 277     @Override
 278     public String getPrefix(final String uri) throws XMLStreamException {
 279         return currentElement.lookupPrefix(uri);
 280     }
 281 
 282     @Override
 283     public void setPrefix(final String prefix, final String uri) throws XMLStreamException {
 284         try {
 285             this.currentElement.addNamespaceDeclaration(prefix, uri);
 286         } catch (SOAPException e) {
 287             throw new XMLStreamException(e);
 288         }
 289     }
 290 
 291     @Override
 292     public void setDefaultNamespace(final String uri) throws XMLStreamException {
 293         setPrefix("", uri);
 294     }
 295 
 296     @Override
 297     public void setNamespaceContext(final NamespaceContext context)throws XMLStreamException {
 298         throw new UnsupportedOperationException();
 299     }
 300 
 301     @Override
 302     public Object getProperty(final String name) throws IllegalArgumentException {
 303         //TODO the following line is to make eclipselink happy ... they are aware of this problem -
 304         if (javax.xml.stream.XMLOutputFactory.IS_REPAIRING_NAMESPACES.equals(name)) return Boolean.FALSE;
 305         return null;
 306     }
 307 
 308     @Override
 309     public NamespaceContext getNamespaceContext() {
 310         return new NamespaceContext() {
 311             public String getNamespaceURI(final String prefix) {
 312                 return currentElement.getNamespaceURI(prefix);
 313             }
 314             public String getPrefix(final String namespaceURI) {
 315                 return currentElement.lookupPrefix(namespaceURI);
 316             }
 317             public Iterator getPrefixes(final String namespaceURI) {
 318                 return new Iterator() {
 319                     String prefix = getPrefix(namespaceURI);
 320                     public boolean hasNext() {
 321                         return (prefix != null);
 322                     }
 323                     public Object next() {
 324                         if (!hasNext()) throw new java.util.NoSuchElementException();
 325                         String next = prefix;
 326                         prefix = null;
 327                         return next;
 328                     }
 329                     public void remove() {}
 330                 };
 331             }
 332         };
 333     }
 334 }