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 }