1 /*
   2  * Copyright (c) 1997, 2017, 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.Locale;
  29 import java.util.logging.Level;
  30 
  31 import javax.xml.namespace.QName;
  32 import javax.xml.soap.*;
  33 
  34 import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
  35 import org.w3c.dom.Element;
  36 
  37 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  38 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
  39 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  40 
  41 public abstract class FaultImpl extends ElementImpl implements SOAPFault {
  42 
  43     /* This can also represent a fault reason element */
  44     protected SOAPFaultElement faultStringElement;
  45 
  46     /* This can also represent a fault role element */
  47     protected SOAPFaultElement faultActorElement;
  48 
  49     protected SOAPFaultElement faultCodeElement;
  50 
  51     protected Detail detail;
  52 
  53     protected FaultImpl(SOAPDocumentImpl ownerDoc, NameImpl name) {
  54         super(ownerDoc, name);
  55     }
  56 
  57     public FaultImpl(SOAPDocumentImpl ownerDoc, Element domElement) {
  58         super(ownerDoc, domElement);
  59     }
  60 
  61     protected abstract NameImpl getDetailName();
  62     protected abstract NameImpl getFaultCodeName();
  63     protected abstract NameImpl getFaultStringName();
  64     protected abstract NameImpl getFaultActorName();
  65     protected abstract DetailImpl createDetail();
  66     protected abstract FaultElementImpl createSOAPFaultElement(String localName);
  67     protected abstract FaultElementImpl createSOAPFaultElement(QName qname);
  68     protected abstract FaultElementImpl createSOAPFaultElement(Name qname);
  69     protected abstract void checkIfStandardFaultCode(String faultCode, String uri) throws SOAPException;
  70     protected abstract void finallySetFaultCode(String faultcode) throws SOAPException;
  71     protected abstract boolean isStandardFaultElement(String localName);
  72     protected abstract QName getDefaultFaultCode();
  73 
  74 
  75     protected void findFaultCodeElement() {
  76         this.faultCodeElement =
  77             (SOAPFaultElement) findAndConvertChildElement(getFaultCodeName());
  78     }
  79 
  80     protected void findFaultActorElement() {
  81         this.faultActorElement =
  82             (SOAPFaultElement) findAndConvertChildElement(getFaultActorName());
  83     }
  84 
  85     protected void findFaultStringElement() {
  86         this.faultStringElement =
  87             (SOAPFaultElement) findAndConvertChildElement(getFaultStringName());
  88     }
  89 
  90     @Override
  91     public void setFaultCode(String faultCode) throws SOAPException {
  92         setFaultCode(
  93             NameImpl.getLocalNameFromTagName(faultCode),
  94             NameImpl.getPrefixFromTagName(faultCode),
  95             null);
  96     }
  97 
  98     public void setFaultCode(String faultCode, String prefix, String uri)
  99         throws SOAPException {
 100 
 101         if (prefix == null || "".equals(prefix)) {
 102             if (uri != null && !"".equals(uri)) {
 103                 prefix = getNamespacePrefix(uri);
 104                 if (prefix == null || "".equals(prefix)) {
 105                     prefix = "ns0";
 106                 }
 107             }
 108         }
 109         if (this.faultCodeElement == null)
 110             findFaultCodeElement();
 111 
 112         if (this.faultCodeElement == null)
 113             this.faultCodeElement = addFaultCodeElement();
 114         else
 115             this.faultCodeElement.removeContents();
 116 
 117         if (uri == null || "".equals(uri)) {
 118             uri = this.faultCodeElement.getNamespaceURI(prefix);
 119         }
 120         if (uri == null || "".equals(uri)) {
 121             if (prefix != null && !"".equals(prefix)) {
 122                 //cannot allow an empty URI for a non-Empty prefix
 123                 log.log(Level.SEVERE, "SAAJ0140.impl.no.ns.URI", new Object[]{prefix + ":" + faultCode});
 124                 throw new SOAPExceptionImpl("Empty/Null NamespaceURI specified for faultCode \"" + prefix + ":" + faultCode + "\"");
 125             } else {
 126                 uri = "";
 127             }
 128         }
 129         checkIfStandardFaultCode(faultCode, uri);
 130         ((FaultElementImpl) this.faultCodeElement).ensureNamespaceIsDeclared(prefix, uri);
 131 
 132         if (prefix == null || "".equals(prefix)) {
 133             finallySetFaultCode(faultCode);
 134         } else {
 135             finallySetFaultCode(prefix + ":" + faultCode);
 136         }
 137     }
 138 
 139     @Override
 140     public void setFaultCode(Name faultCodeQName) throws SOAPException {
 141         setFaultCode(
 142             faultCodeQName.getLocalName(),
 143             faultCodeQName.getPrefix(),
 144             faultCodeQName.getURI());
 145     }
 146 
 147     @Override
 148     public void setFaultCode(QName faultCodeQName) throws SOAPException {
 149         setFaultCode(
 150             faultCodeQName.getLocalPart(),
 151             faultCodeQName.getPrefix(),
 152             faultCodeQName.getNamespaceURI());
 153     }
 154 
 155     protected static QName convertCodeToQName(
 156         String code,
 157         SOAPElement codeContainingElement) {
 158 
 159         int prefixIndex = code.indexOf(':');
 160         if (prefixIndex == -1) {
 161             return new QName(code);
 162         }
 163 
 164         String prefix = code.substring(0, prefixIndex);
 165         String nsName =((ElementImpl) codeContainingElement).lookupNamespaceURI(prefix);
 166             //((ElementImpl) codeContainingElement).getNamespaceURI(prefix);
 167         return new QName(nsName, getLocalPart(code), prefix);
 168     }
 169 
 170     protected void initializeDetail() {
 171         NameImpl detailName = getDetailName();
 172         detail = (Detail) findAndConvertChildElement(detailName);
 173     }
 174 
 175     @Override
 176     public Detail getDetail() {
 177         if (detail == null)
 178             initializeDetail();
 179         if ((detail != null) && (detail.getParentNode() == null)) {
 180         // a detach node was called on it
 181             detail = null;
 182         }
 183         return detail;
 184     }
 185 
 186     @Override
 187     public Detail addDetail() throws SOAPException {
 188         if (detail == null)
 189             initializeDetail();
 190         if (detail == null) {
 191             detail = createDetail();
 192             addNode(detail);
 193             return detail;
 194         } else {
 195             // Log
 196             throw new SOAPExceptionImpl("Error: Detail already exists");
 197         }
 198     }
 199 
 200     @Override
 201     public boolean hasDetail() {
 202         return (getDetail() != null);
 203     }
 204 
 205     @Override
 206     public abstract void setFaultActor(String faultActor) throws SOAPException;
 207 
 208     @Override
 209     public String getFaultActor() {
 210         if (this.faultActorElement == null)
 211             findFaultActorElement();
 212         if (this.faultActorElement != null) {
 213                 return this.faultActorElement.getValue();
 214         }
 215         return null;
 216     }
 217 
 218     @Override
 219     public SOAPElement setElementQName(QName newName) throws SOAPException {
 220 
 221         log.log(
 222             Level.SEVERE,
 223             "SAAJ0146.impl.invalid.name.change.requested",
 224             new Object[] {elementQName.getLocalPart(), newName.getLocalPart()});
 225         throw new SOAPException(
 226             "Cannot change name for " + elementQName.getLocalPart() + " to " + newName.getLocalPart());
 227     }
 228 
 229     @Override
 230     protected SOAPElement convertToSoapElement(Element element) {
 231         final org.w3c.dom.Node soapNode = getSoapDocument().findIfPresent(element);
 232         if (soapNode instanceof SOAPFaultElement) {
 233             return (SOAPElement) soapNode;
 234         } else if (soapNode instanceof SOAPElement) {
 235             SOAPElement soapElement = (SOAPElement) soapNode;
 236             if (getDetailName().equals(soapElement.getElementName())) {
 237                 return replaceElementWithSOAPElement(element, createDetail());
 238             } else {
 239                 String localName =
 240                     soapElement.getElementName().getLocalName();
 241                 if (isStandardFaultElement(localName))
 242                     return replaceElementWithSOAPElement(
 243                                element,
 244                                createSOAPFaultElement(soapElement.getElementQName()));
 245                 return soapElement;
 246             }
 247         } else {
 248             Name elementName = NameImpl.copyElementName(element);
 249             ElementImpl newElement;
 250             if (getDetailName().equals(elementName)) {
 251                 newElement = createDetail();
 252             } else {
 253                 String localName = elementName.getLocalName();
 254                 if (isStandardFaultElement(localName))
 255                     newElement =
 256                         createSOAPFaultElement(elementName);
 257                 else
 258                     newElement = (ElementImpl) createElement(elementName);
 259             }
 260             return replaceElementWithSOAPElement(element, newElement);
 261         }
 262     }
 263 
 264     protected SOAPFaultElement addFaultCodeElement() throws SOAPException {
 265         if (this.faultCodeElement == null)
 266             findFaultCodeElement();
 267         if (this.faultCodeElement == null) {
 268             this.faultCodeElement =
 269                 addSOAPFaultElement(getFaultCodeName().getLocalName());
 270             return this.faultCodeElement;
 271         } else {
 272             throw new SOAPExceptionImpl("Error: Faultcode already exists");
 273         }
 274     }
 275 
 276     private SOAPFaultElement addFaultStringElement() throws SOAPException {
 277         if (this.faultStringElement == null)
 278             findFaultStringElement();
 279         if (this.faultStringElement == null) {
 280             this.faultStringElement =
 281                 addSOAPFaultElement(getFaultStringName().getLocalName());
 282             return this.faultStringElement;
 283         } else {
 284             // Log
 285             throw new SOAPExceptionImpl("Error: Faultstring already exists");
 286         }
 287     }
 288 
 289     private SOAPFaultElement addFaultActorElement() throws SOAPException {
 290         if (this.faultActorElement == null)
 291             findFaultActorElement();
 292         if (this.faultActorElement == null) {
 293             this.faultActorElement =
 294                 addSOAPFaultElement(getFaultActorName().getLocalName());
 295             return this.faultActorElement;
 296         } else {
 297             // Log
 298             throw new SOAPExceptionImpl("Error: Faultactor already exists");
 299         }
 300     }
 301 
 302     @Override
 303     protected SOAPElement addElement(Name name) throws SOAPException {
 304         if (getDetailName().equals(name)) {
 305             return addDetail();
 306         } else if(getFaultCodeName().equals(name)) {
 307             return addFaultCodeElement();
 308         } else if(getFaultStringName().equals(name)) {
 309             return addFaultStringElement();
 310         } else if(getFaultActorName().equals(name)) {
 311             return addFaultActorElement();
 312         }
 313         return super.addElement(name);
 314     }
 315 
 316     @Override
 317     protected SOAPElement addElement(QName name) throws SOAPException {
 318         return addElement(NameImpl.convertToName(name));
 319     }
 320 
 321     protected FaultElementImpl addSOAPFaultElement(String localName)
 322         throws SOAPException {
 323 
 324         FaultElementImpl faultElem = createSOAPFaultElement(localName);
 325         addNode(faultElem);
 326         return faultElem;
 327     }
 328 
 329     /**
 330      * Convert an xml:lang attribute value into a Locale object
 331      * @param xmlLang xml:lang attribute value
 332      * @return Locale
 333      */
 334     protected static Locale xmlLangToLocale(String xmlLang) {
 335         if (xmlLang == null) {
 336             return null;
 337         }
 338 
 339         // Spec uses hyphen as separator
 340         int index = xmlLang.indexOf("-");
 341 
 342         // Accept underscore as separator as well
 343         if (index == -1) {
 344             index = xmlLang.indexOf("_");
 345         }
 346 
 347         if (index == -1) {
 348             // No separator so assume only a language component
 349             return new Locale(xmlLang, "");
 350         }
 351 
 352         String language = xmlLang.substring(0, index);
 353         String country = xmlLang.substring(index + 1);
 354         return new Locale(language, country);
 355     }
 356 
 357     protected static String localeToXmlLang(Locale locale) {
 358         String xmlLang = locale.getLanguage();
 359         String country = locale.getCountry();
 360         if (!"".equals(country)) {
 361             xmlLang += "-" + country;
 362         }
 363         return xmlLang;
 364     }
 365 }