Fault1_2Impl.java revision 756:311b931e5485
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*/
30package com.sun.xml.internal.messaging.saaj.soap.ver1_2;
31
32import java.util.*;
33import java.util.logging.Logger;
34import java.util.logging.Level;
35
36import javax.xml.namespace.QName;
37import javax.xml.soap.*;
38
39import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
40import com.sun.xml.internal.messaging.saaj.soap.SOAPDocument;
41import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
42import com.sun.xml.internal.messaging.saaj.soap.impl.*;
43import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
44import com.sun.xml.internal.messaging.saaj.util.LogDomainConstants;
45import org.w3c.dom.Element;
46
47
48public 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}
568