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