1 /*
   2  * Copyright (c) 1997, 2010, 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.parsers.DocumentBuilder;
  35 import javax.xml.parsers.DocumentBuilderFactory;
  36 
  37 import org.w3c.dom.*;
  38 
  39 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  40 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument;
  41 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
  42 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  43 
  44 /**
  45  * The implementation of SOAP-ENV:BODY or the SOAPBody abstraction.
  46  *
  47  * @author Anil Vijendran (anil@sun.com)
  48  */
  49 public abstract class BodyImpl extends ElementImpl implements SOAPBody {
  50     private SOAPFault fault;
  51 
  52     protected BodyImpl(SOAPDocumentImpl ownerDoc, NameImpl bodyName) {
  53         super(ownerDoc, bodyName);
  54     }
  55 
  56     protected abstract NameImpl getFaultName(String name);
  57     protected abstract boolean isFault(SOAPElement child);
  58     protected abstract SOAPBodyElement createBodyElement(Name name);
  59     protected abstract SOAPBodyElement createBodyElement(QName name);
  60     protected abstract SOAPFault createFaultElement();
  61     protected abstract QName getDefaultFaultCode();
  62 
  63     public SOAPFault addFault() throws SOAPException {
  64         if (hasFault()) {
  65             log.severe("SAAJ0110.impl.fault.already.exists");
  66             throw new SOAPExceptionImpl("Error: Fault already exists");
  67         }
  68 
  69         fault = createFaultElement();
  70 
  71         addNode(fault);
  72 
  73         fault.setFaultCode(getDefaultFaultCode());
  74         fault.setFaultString("Fault string, and possibly fault code, not set");
  75 
  76         return fault;
  77     }
  78 
  79     public SOAPFault addFault(
  80         Name faultCode,
  81         String faultString,
  82         Locale locale)
  83         throws SOAPException {
  84 
  85         SOAPFault fault = addFault();
  86         fault.setFaultCode(faultCode);
  87         fault.setFaultString(faultString, locale);
  88         return fault;
  89     }
  90 
  91    public SOAPFault addFault(
  92         QName faultCode,
  93         String faultString,
  94         Locale locale)
  95         throws SOAPException {
  96 
  97         SOAPFault fault = addFault();
  98         fault.setFaultCode(faultCode);
  99         fault.setFaultString(faultString, locale);
 100         return fault;
 101     }
 102 
 103     public SOAPFault addFault(Name faultCode, String faultString)
 104         throws SOAPException {
 105 
 106         SOAPFault fault = addFault();
 107         fault.setFaultCode(faultCode);
 108         fault.setFaultString(faultString);
 109         return fault;
 110     }
 111 
 112     public SOAPFault addFault(QName faultCode, String faultString)
 113         throws SOAPException {
 114 
 115         SOAPFault fault = addFault();
 116         fault.setFaultCode(faultCode);
 117         fault.setFaultString(faultString);
 118         return fault;
 119     }
 120 
 121     void initializeFault() {
 122         FaultImpl flt = (FaultImpl) findFault();
 123         fault = flt;
 124     }
 125 
 126     protected SOAPElement findFault() {
 127         Iterator eachChild = getChildElementNodes();
 128         while (eachChild.hasNext()) {
 129             SOAPElement child = (SOAPElement) eachChild.next();
 130             if (isFault(child)) {
 131                 return child;
 132             }
 133         }
 134 
 135         return null;
 136     }
 137 
 138     public boolean hasFault() {
 139         initializeFault();
 140         return fault != null;
 141     }
 142 
 143     public SOAPFault getFault() {
 144         if (hasFault())
 145             return fault;
 146         return null;
 147     }
 148 
 149     public SOAPBodyElement addBodyElement(Name name) throws SOAPException {
 150         SOAPBodyElement newBodyElement =
 151             (SOAPBodyElement) ElementFactory.createNamedElement(
 152                 ((SOAPDocument) getOwnerDocument()).getDocument(),
 153                 name.getLocalName(),
 154                 name.getPrefix(),
 155                 name.getURI());
 156         if (newBodyElement == null) {
 157             newBodyElement = createBodyElement(name);
 158         }
 159         addNode(newBodyElement);
 160         return newBodyElement;
 161     }
 162 
 163     public SOAPBodyElement addBodyElement(QName qname) throws SOAPException {
 164         SOAPBodyElement newBodyElement =
 165             (SOAPBodyElement) ElementFactory.createNamedElement(
 166                 ((SOAPDocument) getOwnerDocument()).getDocument(),
 167                 qname.getLocalPart(),
 168                 qname.getPrefix(),
 169                 qname.getNamespaceURI());
 170         if (newBodyElement == null) {
 171             newBodyElement = createBodyElement(qname);
 172         }
 173         addNode(newBodyElement);
 174         return newBodyElement;
 175     }
 176 
 177     public void setParentElement(SOAPElement element) throws SOAPException {
 178 
 179         if (!(element instanceof SOAPEnvelope)) {
 180             log.severe("SAAJ0111.impl.body.parent.must.be.envelope");
 181             throw new SOAPException("Parent of SOAPBody has to be a SOAPEnvelope");
 182         }
 183         super.setParentElement(element);
 184     }
 185 
 186     protected SOAPElement addElement(Name name) throws SOAPException {
 187         return addBodyElement(name);
 188     }
 189 
 190     protected SOAPElement addElement(QName name) throws SOAPException {
 191         return addBodyElement(name);
 192     }
 193 
 194     //    public Node insertBefore(Node newElement, Node ref) throws DOMException {
 195     //        if (!(newElement instanceof SOAPBodyElement) && (newElement instanceof SOAPElement)) {
 196     //            newElement = new ElementWrapper((ElementImpl) newElement);
 197     //        }
 198     //        return super.insertBefore(newElement, ref);
 199     //    }
 200     //
 201     //    public Node replaceChild(Node newElement, Node ref) throws DOMException {
 202     //        if (!(newElement instanceof SOAPBodyElement) && (newElement instanceof SOAPElement)) {
 203     //            newElement = new ElementWrapper((ElementImpl) newElement);
 204     //        }
 205     //        return super.replaceChild(newElement, ref);
 206     //    }
 207 
 208     public SOAPBodyElement addDocument(Document document)
 209         throws SOAPException {
 210         /*
 211 
 212                 Element rootNode =
 213                     document.getDocumentElement();
 214                 // Causes all deferred nodes to be inflated
 215                 rootNode.normalize();
 216                 adoptElement(rootNode);
 217                 SOAPBodyElement bodyElement = (SOAPBodyElement) convertToSoapElement(rootNode);
 218                 addNode(bodyElement);
 219                 return bodyElement;
 220         */
 221         ///*
 222         SOAPBodyElement newBodyElement = null;
 223         DocumentFragment docFrag = document.createDocumentFragment();
 224         Element rootElement = document.getDocumentElement();
 225         if(rootElement != null) {
 226             docFrag.appendChild(rootElement);
 227 
 228             Document ownerDoc = getOwnerDocument();
 229             // This copies the whole tree which could be very big so it's slow.
 230             // However, it does have the advantage of actually working.
 231             org.w3c.dom.Node replacingNode = ownerDoc.importNode(docFrag, true);
 232             // Adding replacingNode at the last of the children list of body
 233             addNode(replacingNode);
 234             Iterator i =
 235                 getChildElements(NameImpl.copyElementName(rootElement));
 236             // Return the child element with the required name which is at the
 237             // end of the list
 238             while(i.hasNext())
 239                 newBodyElement = (SOAPBodyElement) i.next();
 240         }
 241         return newBodyElement;
 242         //*/
 243     }
 244 
 245     protected SOAPElement convertToSoapElement(Element element) {
 246         if ((element instanceof SOAPBodyElement) &&
 247             //this check is required because ElementImpl currently
 248             // implements SOAPBodyElement
 249             !(element.getClass().equals(ElementImpl.class))) {
 250             return (SOAPElement) element;
 251         } else {
 252             return replaceElementWithSOAPElement(
 253                 element,
 254                 (ElementImpl) createBodyElement(NameImpl
 255                     .copyElementName(element)));
 256         }
 257     }
 258 
 259     public SOAPElement setElementQName(QName newName) throws SOAPException {
 260         log.log(Level.SEVERE,
 261                 "SAAJ0146.impl.invalid.name.change.requested",
 262                 new Object[] {elementQName.getLocalPart(),
 263                               newName.getLocalPart()});
 264         throw new SOAPException("Cannot change name for "
 265                                 + elementQName.getLocalPart() + " to "
 266                                 + newName.getLocalPart());
 267     }
 268 
 269     public Document extractContentAsDocument() throws SOAPException {
 270 
 271         Iterator eachChild = getChildElements();
 272         javax.xml.soap.Node firstBodyElement = null;
 273 
 274         while (eachChild.hasNext() &&
 275                !(firstBodyElement instanceof SOAPElement))
 276             firstBodyElement = (javax.xml.soap.Node) eachChild.next();
 277 
 278         boolean exactlyOneChildElement = true;
 279         if (firstBodyElement == null)
 280             exactlyOneChildElement = false;
 281         else {
 282             for (org.w3c.dom.Node node = firstBodyElement.getNextSibling();
 283                  node != null;
 284                  node = node.getNextSibling()) {
 285 
 286                 if (node instanceof Element) {
 287                     exactlyOneChildElement = false;
 288                     break;
 289                 }
 290             }
 291         }
 292 
 293         if(!exactlyOneChildElement) {
 294             log.log(Level.SEVERE,
 295                     "SAAJ0250.impl.body.should.have.exactly.one.child");
 296             throw new SOAPException("Cannot extract Document from body");
 297         }
 298 
 299         Document document = null;
 300         try {
 301             DocumentBuilderFactory factory =
 302                 new com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl();
 303             factory.setNamespaceAware(true);
 304             DocumentBuilder builder = factory.newDocumentBuilder();
 305             document = builder.newDocument();
 306 
 307             Element rootElement = (Element) document.importNode(
 308                                                 firstBodyElement,
 309                                                 true);
 310 
 311             document.appendChild(rootElement);
 312 
 313         } catch(Exception e) {
 314             log.log(Level.SEVERE,
 315                     "SAAJ0251.impl.cannot.extract.document.from.body");
 316             throw new SOAPExceptionImpl(
 317                 "Unable to extract Document from body", e);
 318         }
 319 
 320         firstBodyElement.detachNode();
 321 
 322         return document;
 323     }
 324 
 325 }