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 /**
  27 *
  28 * @author SAAJ RI Development Team
  29 */
  30 package com.sun.xml.internal.messaging.saaj.soap.ver1_2;
  31 
  32 import java.util.logging.Logger;
  33 import java.util.logging.Level;
  34 
  35 import javax.xml.namespace.QName;
  36 
  37 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
  38 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument;
  39 import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
  40 import com.sun.xml.internal.messaging.saaj.soap.impl.*;
  41 import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
  42 import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants;
  43 import java.util.ArrayList;
  44 import java.util.Iterator;
  45 import java.util.List;
  46 import java.util.Locale;
  47 import javax.xml.soap.Name;
  48 import javax.xml.soap.SOAPConstants;
  49 import javax.xml.soap.SOAPElement;
  50 import javax.xml.soap.SOAPException;
  51 import org.w3c.dom.Element;
  52 
  53 
  54 public class Fault1_2Impl extends FaultImpl {
  55 
  56     protected static final Logger log =
  57         Logger.getLogger(
  58             LogDomainConstants.SOAP_VER1_2_DOMAIN,
  59             "com.sun.xml.internal.messaging.saaj.soap.ver1_2.LocalStrings");
  60 
  61     private static final QName textName =
  62         new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "Text");
  63     private final QName valueName =
  64         new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "Value", getPrefix());
  65     private final QName subcodeName =
  66         new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "Subcode", getPrefix());
  67 
  68     private SOAPElement innermostSubCodeElement = null;
  69 
  70     public Fault1_2Impl(SOAPDocumentImpl ownerDoc, String name, String prefix) {
  71         super(ownerDoc, NameImpl.createFault1_2Name(name, prefix));
  72     }
  73 
  74     public Fault1_2Impl(SOAPDocumentImpl ownerDocument, String prefix) {
  75         super(ownerDocument, NameImpl.createFault1_2Name(null, prefix));
  76     }
  77 
  78     public Fault1_2Impl(Element domElement, SOAPDocumentImpl ownerDoc) {
  79         super(ownerDoc, domElement);
  80     }
  81 
  82     @Override
  83     protected NameImpl getDetailName() {
  84         return NameImpl.createSOAP12Name("Detail", getPrefix());
  85     }
  86 
  87     @Override
  88     protected NameImpl getFaultCodeName() {
  89         return NameImpl.createSOAP12Name("Code", getPrefix());
  90     }
  91 
  92     @Override
  93     protected NameImpl getFaultStringName() {
  94         return getFaultReasonName();
  95     }
  96 
  97     @Override
  98     protected NameImpl getFaultActorName() {
  99         return getFaultRoleName();
 100     }
 101 
 102     private  NameImpl getFaultRoleName() {
 103         return NameImpl.createSOAP12Name("Role", getPrefix());
 104     }
 105 
 106     private  NameImpl getFaultReasonName() {
 107         return NameImpl.createSOAP12Name("Reason", getPrefix());
 108     }
 109 
 110     private  NameImpl getFaultReasonTextName() {
 111         return NameImpl.createSOAP12Name("Text", getPrefix());
 112     }
 113 
 114     private  NameImpl getFaultNodeName() {
 115         return NameImpl.createSOAP12Name("Node", getPrefix());
 116     }
 117 
 118     private static NameImpl getXmlLangName() {
 119         return NameImpl.createXmlName("lang");
 120     }
 121 
 122     @Override
 123     protected DetailImpl createDetail() {
 124         return new Detail1_2Impl(
 125                        ((SOAPDocument) getOwnerDocument()).getDocument());
 126     }
 127 
 128     @Override
 129     protected FaultElementImpl createSOAPFaultElement(String localName) {
 130         return new FaultElement1_2Impl(
 131                        ((SOAPDocument) getOwnerDocument()).getDocument(),
 132                        localName);
 133     }
 134 
 135     @Override
 136     protected void checkIfStandardFaultCode(String faultCode, String uri)
 137         throws SOAPException {
 138         QName qname = new QName(uri, faultCode);
 139         if (SOAPConstants.SOAP_DATAENCODINGUNKNOWN_FAULT.equals(qname) ||
 140             SOAPConstants.SOAP_MUSTUNDERSTAND_FAULT.equals(qname) ||
 141             SOAPConstants.SOAP_RECEIVER_FAULT.equals(qname) ||
 142             SOAPConstants.SOAP_SENDER_FAULT.equals(qname) ||
 143             SOAPConstants.SOAP_VERSIONMISMATCH_FAULT.equals(qname))
 144             return;
 145         log.log(
 146             Level.SEVERE,
 147             "SAAJ0435.ver1_2.code.not.standard",
 148             qname);
 149         throw new SOAPExceptionImpl(qname + " is not a standard Code value");
 150     }
 151 
 152     @Override
 153     protected void finallySetFaultCode(String faultcode) throws SOAPException {
 154         SOAPElement value = this.faultCodeElement.addChildElement(valueName);
 155         value.addTextNode(faultcode);
 156     }
 157 
 158     private void findReasonElement() {
 159         findFaultStringElement();
 160     }
 161 
 162     @Override
 163     public Iterator<String> getFaultReasonTexts() throws SOAPException {
 164         // Fault Reason has similar semantics as faultstring
 165         if (this.faultStringElement == null)
 166             findReasonElement();
 167         Iterator eachTextElement =
 168             this.faultStringElement.getChildElements(textName);
 169         List<String> texts = new ArrayList<>();
 170         while (eachTextElement.hasNext()) {
 171             SOAPElement textElement = (SOAPElement) eachTextElement.next();
 172             Locale thisLocale = getLocale(textElement);
 173             if (thisLocale == null) {
 174                 log.severe("SAAJ0431.ver1_2.xml.lang.missing");
 175                 throw new SOAPExceptionImpl("\"xml:lang\" attribute is not present on the Text element");
 176             }
 177             texts.add(textElement.getValue());
 178         }
 179         if (texts.isEmpty()) {
 180             log.severe("SAAJ0434.ver1_2.text.element.not.present");
 181             throw new SOAPExceptionImpl("env:Text must be present inside env:Reason");
 182         }
 183         return texts.iterator();
 184     }
 185 
 186     @Override
 187     public void addFaultReasonText(String text, java.util.Locale locale)
 188         throws SOAPException {
 189 
 190         if (locale == null) {
 191             log.severe("SAAJ0430.ver1_2.locale.required");
 192             throw new SOAPException("locale is required and must not be null");
 193         }
 194 
 195         // Fault Reason has similar semantics as faultstring
 196         if (this.faultStringElement == null)
 197             findReasonElement();
 198         SOAPElement reasonText;
 199 
 200         if (this.faultStringElement == null) {
 201             this.faultStringElement = addSOAPFaultElement("Reason");
 202             reasonText =
 203                 this.faultStringElement.addChildElement(
 204                     getFaultReasonTextName());
 205         } else {
 206             removeDefaultFaultString();
 207             reasonText = getFaultReasonTextElement(locale);
 208             if (reasonText != null) {
 209                 reasonText.removeContents();
 210             } else {
 211                 reasonText =
 212                     this.faultStringElement.addChildElement(
 213                         getFaultReasonTextName());
 214             }
 215         }
 216 
 217         String xmlLang = localeToXmlLang(locale);
 218         reasonText.addAttribute(getXmlLangName(), xmlLang);
 219         reasonText.addTextNode(text);
 220     }
 221 
 222     private void removeDefaultFaultString() throws SOAPException {
 223         SOAPElement reasonText = getFaultReasonTextElement(Locale.getDefault());
 224         if (reasonText != null) {
 225             String defaultFaultString =
 226                 "Fault string, and possibly fault code, not set";
 227             if (defaultFaultString.equals(reasonText.getValue())) {
 228                 reasonText.detachNode();
 229             }
 230         }
 231     }
 232 
 233     @Override
 234     public String getFaultReasonText(Locale locale) throws SOAPException {
 235 
 236         if (locale == null)
 237             return null;
 238 
 239         // Fault Reason has similar semantics as faultstring
 240         if (this.faultStringElement == null)
 241             findReasonElement();
 242 
 243         if (this.faultStringElement != null) {
 244             SOAPElement textElement = getFaultReasonTextElement(locale);
 245             if (textElement != null) {
 246                 textElement.normalize();
 247                 return textElement.getFirstChild().getNodeValue();
 248             }
 249         }
 250 
 251         return null;
 252     }
 253 
 254     @Override
 255     public Iterator<Locale> getFaultReasonLocales() throws SOAPException {
 256         // Fault Reason has similar semantics as faultstring
 257         if (this.faultStringElement == null)
 258             findReasonElement();
 259         Iterator eachTextElement =
 260             this.faultStringElement.getChildElements(textName);
 261         List<Locale> localeSet = new ArrayList<>();
 262         while (eachTextElement.hasNext()) {
 263             SOAPElement textElement = (SOAPElement) eachTextElement.next();
 264             Locale thisLocale = getLocale(textElement);
 265             if (thisLocale == null) {
 266                 log.severe("SAAJ0431.ver1_2.xml.lang.missing");
 267                 throw new SOAPExceptionImpl("\"xml:lang\" attribute is not present on the Text element");
 268             }
 269             localeSet.add(thisLocale);
 270         }
 271         if (localeSet.isEmpty()) {
 272             log.severe("SAAJ0434.ver1_2.text.element.not.present");
 273             throw new SOAPExceptionImpl("env:Text elements with mandatory xml:lang attributes must be present inside env:Reason");
 274         }
 275         return localeSet.iterator();
 276     }
 277 
 278     @Override
 279     public Locale getFaultStringLocale() {
 280         Locale locale = null;
 281         try {
 282             locale = (Locale) getFaultReasonLocales().next();
 283         } catch (SOAPException e) {}
 284         return locale;
 285     }
 286 
 287     /*
 288      * This method assumes that locale and faultStringElement are non-null
 289      */
 290     private SOAPElement getFaultReasonTextElement(Locale locale)
 291         throws SOAPException {
 292 
 293         // Fault Reason has similar semantics as faultstring
 294         Iterator eachTextElement =
 295             this.faultStringElement.getChildElements(textName);
 296         while (eachTextElement.hasNext()) {
 297             SOAPElement textElement = (SOAPElement) eachTextElement.next();
 298             Locale thisLocale = getLocale(textElement);
 299             if (thisLocale == null) {
 300                 log.severe("SAAJ0431.ver1_2.xml.lang.missing");
 301                 throw new SOAPExceptionImpl("\"xml:lang\" attribute is not present on the Text element");
 302             }
 303             if (thisLocale.equals(locale)) {
 304                 return textElement;
 305             }
 306         }
 307         return null;
 308     }
 309 
 310     @Override
 311     public String getFaultNode() {
 312         SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName());
 313         if (faultNode == null) {
 314             return null;
 315         }
 316         return faultNode.getValue();
 317     }
 318 
 319     @Override
 320     public void setFaultNode(String uri) throws SOAPException {
 321         SOAPElement faultNode = findAndConvertChildElement(getFaultNodeName());
 322         if (faultNode != null) {
 323             faultNode.detachNode();
 324         }
 325         faultNode = createSOAPFaultElement(getFaultNodeName());
 326         faultNode = faultNode.addTextNode(uri);
 327         if (getFaultRole() != null) {
 328             insertBefore(faultNode, this.faultActorElement);
 329             return;
 330         }
 331         if (hasDetail()) {
 332             insertBefore(faultNode, this.detail);
 333             return;
 334         }
 335         addNode(faultNode);
 336     }
 337 
 338     @Override
 339     public String getFaultRole() {
 340         return getFaultActor();
 341     }
 342 
 343     @Override
 344     public void setFaultRole(String uri) throws SOAPException {
 345         if (this.faultActorElement == null)
 346             findFaultActorElement();
 347         if (this.faultActorElement != null)
 348             this.faultActorElement.detachNode();
 349         this.faultActorElement =
 350             createSOAPFaultElement(getFaultActorName());
 351         this.faultActorElement.addTextNode(uri);
 352         if (hasDetail()) {
 353             insertBefore(this.faultActorElement, this.detail);
 354             return;
 355         }
 356         addNode(this.faultActorElement);
 357     }
 358 
 359     @Override
 360     public String getFaultCode() {
 361         if (this.faultCodeElement == null)
 362             findFaultCodeElement();
 363         Iterator codeValues =
 364             this.faultCodeElement.getChildElements(valueName);
 365         return ((SOAPElement) codeValues.next()).getValue();
 366     }
 367 
 368     @Override
 369     public QName getFaultCodeAsQName() {
 370         String faultcode = getFaultCode();
 371         if (faultcode == null) {
 372             return null;
 373         }
 374         if (this.faultCodeElement == null)
 375             findFaultCodeElement();
 376         Iterator valueElements =
 377             this.faultCodeElement.getChildElements(valueName);
 378         return convertCodeToQName(
 379             faultcode,
 380             (SOAPElement) valueElements.next());
 381     }
 382 
 383     @Override
 384     public Name getFaultCodeAsName() {
 385         String faultcode = getFaultCode();
 386         if (faultcode == null) {
 387             return null;
 388         }
 389         if (this.faultCodeElement == null)
 390             findFaultCodeElement();
 391         Iterator valueElements =
 392             this.faultCodeElement.getChildElements(valueName);
 393         return NameImpl.convertToName(
 394             convertCodeToQName(
 395                 faultcode,
 396                 (SOAPElement) valueElements.next()));
 397     }
 398 
 399     @Override
 400     public String getFaultString() {
 401         String reason = null;
 402         try {
 403             //reason = getFaultReasonText(Locale.getDefault());
 404             //if (reason == null)
 405             reason = (String) getFaultReasonTexts().next();
 406         } catch (SOAPException e) {}
 407         return reason;
 408     }
 409 
 410     @Override
 411     public void setFaultString(String faultString) throws SOAPException {
 412         addFaultReasonText(faultString, Locale.getDefault());
 413     }
 414 
 415     @Override
 416     public void setFaultString(
 417         String faultString,
 418         Locale locale)
 419         throws SOAPException {
 420         addFaultReasonText(faultString, locale);
 421     }
 422 
 423     @Override
 424     public void appendFaultSubcode(QName subcode) throws SOAPException {
 425         if (subcode == null) {
 426             return;
 427         }
 428         if (subcode.getNamespaceURI() == null ||
 429             "".equals(subcode.getNamespaceURI())) {
 430 
 431             log.severe("SAAJ0432.ver1_2.subcode.not.ns.qualified");
 432             throw new SOAPExceptionImpl("A Subcode must be namespace-qualified");
 433         }
 434         if (innermostSubCodeElement == null) {
 435             if (faultCodeElement == null)
 436                 findFaultCodeElement();
 437             innermostSubCodeElement = faultCodeElement;
 438         }
 439         String prefix = null;
 440         if (subcode.getPrefix() == null || "".equals(subcode.getPrefix())) {
 441             prefix =
 442                 ((ElementImpl) innermostSubCodeElement).getNamespacePrefix(
 443                     subcode.getNamespaceURI());
 444         } else
 445             prefix = subcode.getPrefix();
 446         if (prefix == null || "".equals(prefix)) {
 447             prefix = "ns1";
 448         }
 449         innermostSubCodeElement =
 450             innermostSubCodeElement.addChildElement(subcodeName);
 451         SOAPElement subcodeValueElement =
 452             innermostSubCodeElement.addChildElement(valueName);
 453         ((ElementImpl) subcodeValueElement).ensureNamespaceIsDeclared(
 454             prefix,
 455             subcode.getNamespaceURI());
 456         subcodeValueElement.addTextNode(prefix + ":" + subcode.getLocalPart());
 457     }
 458 
 459     @Override
 460     public void removeAllFaultSubcodes() {
 461         if (this.faultCodeElement == null)
 462             findFaultCodeElement();
 463         Iterator subcodeElements =
 464             this.faultCodeElement.getChildElements(subcodeName);
 465         if (subcodeElements.hasNext()) {
 466             SOAPElement subcode = (SOAPElement) subcodeElements.next();
 467             subcode.detachNode();
 468         }
 469     }
 470 
 471     @Override
 472     public Iterator<QName> getFaultSubcodes() {
 473         if (this.faultCodeElement == null)
 474             findFaultCodeElement();
 475         final List<QName> subcodeList = new ArrayList<>();
 476         SOAPElement currentCodeElement = this.faultCodeElement;
 477         Iterator subcodeElements =
 478             currentCodeElement.getChildElements(subcodeName);
 479         while (subcodeElements.hasNext()) {
 480             currentCodeElement = (ElementImpl) subcodeElements.next();
 481             Iterator valueElements =
 482                 currentCodeElement.getChildElements(valueName);
 483             SOAPElement valueElement = (SOAPElement) valueElements.next();
 484             String code = valueElement.getValue();
 485             subcodeList.add(convertCodeToQName(code, valueElement));
 486             subcodeElements = currentCodeElement.getChildElements(subcodeName);
 487         }
 488         //return subcodeList.iterator();
 489         return new Iterator<QName>() {
 490             Iterator<QName> subCodeIter = subcodeList.iterator();
 491 
 492             @Override
 493             public boolean hasNext() {
 494                 return subCodeIter.hasNext();
 495             }
 496 
 497             @Override
 498             public QName next() {
 499                 return subCodeIter.next();
 500             }
 501 
 502             @Override
 503             public void remove() {
 504                 throw new UnsupportedOperationException(
 505                     "Method remove() not supported on SubCodes Iterator");
 506             }
 507         };
 508     }
 509 
 510     private static Locale getLocale(SOAPElement reasonText) {
 511         return xmlLangToLocale(reasonText.getAttributeValue(getXmlLangName()));
 512     }
 513 
 514     /*
 515      * Override setEncodingStyle of ElementImpl to restrict adding encodingStyle
 516      * attribute to SOAP Fault (SOAP 1.2 spec, part 1, section 5.1.1)
 517      */
 518     @Override
 519     public void setEncodingStyle(String encodingStyle) throws SOAPException {
 520         log.severe("SAAJ0407.ver1_2.no.encodingStyle.in.fault");
 521         throw new SOAPExceptionImpl("encodingStyle attribute cannot appear on Fault");
 522     }
 523 
 524     @Override
 525     public SOAPElement addAttribute(Name name, String value)
 526         throws SOAPException {
 527         if (name.getLocalName().equals("encodingStyle")
 528             && name.getURI().equals(NameImpl.SOAP12_NAMESPACE)) {
 529             setEncodingStyle(value);
 530         }
 531         return super.addAttribute(name, value);
 532     }
 533 
 534     @Override
 535     public SOAPElement addAttribute(QName name, String value)
 536         throws SOAPException {
 537         if (name.getLocalPart().equals("encodingStyle")
 538             && name.getNamespaceURI().equals(NameImpl.SOAP12_NAMESPACE)) {
 539             setEncodingStyle(value);
 540         }
 541         return super.addAttribute(name, value);
 542     }
 543 
 544     @Override
 545     public SOAPElement addTextNode(String text) throws SOAPException {
 546         log.log(
 547             Level.SEVERE,
 548             "SAAJ0416.ver1_2.adding.text.not.legal",
 549             getElementQName());
 550         throw new SOAPExceptionImpl("Adding text to SOAP 1.2 Fault is not legal");
 551     }
 552 
 553     @Override
 554     public SOAPElement addChildElement(SOAPElement element)
 555         throws SOAPException {
 556         String localName = element.getLocalName();
 557         if ("Detail".equalsIgnoreCase(localName)) {
 558             if (hasDetail()) {
 559                 log.severe("SAAJ0436.ver1_2.detail.exists.error");
 560                 throw new SOAPExceptionImpl("Cannot add Detail, Detail already exists");
 561             }
 562             String uri = element.getElementQName().getNamespaceURI();
 563             if (!uri.equals(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE)) {
 564                 log.severe("SAAJ0437.ver1_2.version.mismatch.error");
 565                 throw new SOAPExceptionImpl("Cannot add Detail, Incorrect SOAP version specified for Detail element");
 566             }
 567         }
 568         if (element instanceof Detail1_2Impl) {
 569             Element importedElement = importElement(element);
 570             addNode(importedElement);
 571             return convertToSoapElement(importedElement);
 572         } else
 573             return super.addChildElement(element);
 574     }
 575 
 576     @Override
 577     protected boolean isStandardFaultElement(String localName) {
 578         if (localName.equalsIgnoreCase("code") ||
 579             localName.equalsIgnoreCase("reason") ||
 580             localName.equalsIgnoreCase("node") ||
 581             localName.equalsIgnoreCase("role") ||
 582             localName.equalsIgnoreCase("detail")) {
 583             return true;
 584         }
 585         return false;
 586     }
 587 
 588     @Override
 589     protected QName getDefaultFaultCode() {
 590         return SOAPConstants.SOAP_SENDER_FAULT;
 591     }
 592 
 593     @Override
 594      protected FaultElementImpl createSOAPFaultElement(QName qname) {
 595          return new FaultElement1_2Impl(
 596                        ((SOAPDocument) getOwnerDocument()).getDocument(),
 597                        qname);
 598     }
 599 
 600     @Override
 601     protected FaultElementImpl createSOAPFaultElement(Name qname) {
 602          return new FaultElement1_2Impl(
 603                        ((SOAPDocument) getOwnerDocument()).getDocument(),
 604                        (NameImpl)qname);
 605     }
 606 
 607     @Override
 608      public void setFaultActor(String faultActor) throws SOAPException {
 609         this.setFaultRole(faultActor);
 610     }
 611 
 612 }