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 }