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