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 }