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