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
26package com.sun.xml.internal.messaging.saaj.soap.impl;
27
28import java.util.Locale;
29import java.util.logging.Level;
30
31import javax.xml.namespace.QName;
32import javax.xml.soap.*;
33
34import com.sun.xml.internal.messaging.saaj.util.SAAJUtil;
35import org.w3c.dom.Element;
36
37import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
38import com.sun.xml.internal.messaging.saaj.soap.SOAPDocumentImpl;
39import com.sun.xml.internal.messaging.saaj.soap.name.NameImpl;
40
41public abstract class FaultImpl extends ElementImpl implements SOAPFault {
42
43    /* This can also represent a fault reason element */
44    protected SOAPFaultElement faultStringElement;
45
46    /* This can also represent a fault role element */
47    protected SOAPFaultElement faultActorElement;
48
49    protected SOAPFaultElement faultCodeElement;
50
51    protected Detail detail;
52
53    protected FaultImpl(SOAPDocumentImpl ownerDoc, NameImpl name) {
54        super(ownerDoc, name);
55    }
56
57    public FaultImpl(SOAPDocumentImpl ownerDoc, Element domElement) {
58        super(ownerDoc, domElement);
59    }
60
61    protected abstract NameImpl getDetailName();
62    protected abstract NameImpl getFaultCodeName();
63    protected abstract NameImpl getFaultStringName();
64    protected abstract NameImpl getFaultActorName();
65    protected abstract DetailImpl createDetail();
66    protected abstract FaultElementImpl createSOAPFaultElement(String localName);
67    protected abstract FaultElementImpl createSOAPFaultElement(QName qname);
68    protected abstract FaultElementImpl createSOAPFaultElement(Name qname);
69    protected abstract void checkIfStandardFaultCode(String faultCode, String uri) throws SOAPException;
70    protected abstract void finallySetFaultCode(String faultcode) throws SOAPException;
71    protected abstract boolean isStandardFaultElement(String localName);
72    protected abstract QName getDefaultFaultCode();
73
74
75    protected void findFaultCodeElement() {
76        this.faultCodeElement =
77            (SOAPFaultElement) findAndConvertChildElement(getFaultCodeName());
78    }
79
80    protected void findFaultActorElement() {
81        this.faultActorElement =
82            (SOAPFaultElement) findAndConvertChildElement(getFaultActorName());
83    }
84
85    protected void findFaultStringElement() {
86        this.faultStringElement =
87            (SOAPFaultElement) findAndConvertChildElement(getFaultStringName());
88    }
89
90    @Override
91    public void setFaultCode(String faultCode) throws SOAPException {
92        setFaultCode(
93            NameImpl.getLocalNameFromTagName(faultCode),
94            NameImpl.getPrefixFromTagName(faultCode),
95            null);
96    }
97
98    public void setFaultCode(String faultCode, String prefix, String uri)
99        throws SOAPException {
100
101        if (prefix == null || "".equals(prefix)) {
102            if (uri != null && !"".equals(uri)) {
103                prefix = getNamespacePrefix(uri);
104                if (prefix == null || "".equals(prefix)) {
105                    prefix = "ns0";
106                }
107            }
108        }
109        if (this.faultCodeElement == null)
110            findFaultCodeElement();
111
112        if (this.faultCodeElement == null)
113            this.faultCodeElement = addFaultCodeElement();
114        else
115            this.faultCodeElement.removeContents();
116
117        if (uri == null || "".equals(uri)) {
118            uri = this.faultCodeElement.getNamespaceURI(prefix);
119        }
120        if (uri == null || "".equals(uri)) {
121            if (prefix != null && !"".equals(prefix)) {
122                //cannot allow an empty URI for a non-Empty prefix
123                log.log(Level.SEVERE, "SAAJ0140.impl.no.ns.URI", new Object[]{prefix + ":" + faultCode});
124                throw new SOAPExceptionImpl("Empty/Null NamespaceURI specified for faultCode \"" + prefix + ":" + faultCode + "\"");
125            } else {
126                uri = "";
127            }
128        }
129        checkIfStandardFaultCode(faultCode, uri);
130        ((FaultElementImpl) this.faultCodeElement).ensureNamespaceIsDeclared(prefix, uri);
131
132        if (prefix == null || "".equals(prefix)) {
133            finallySetFaultCode(faultCode);
134        } else {
135            finallySetFaultCode(prefix + ":" + faultCode);
136        }
137    }
138
139    @Override
140    public void setFaultCode(Name faultCodeQName) throws SOAPException {
141        setFaultCode(
142            faultCodeQName.getLocalName(),
143            faultCodeQName.getPrefix(),
144            faultCodeQName.getURI());
145    }
146
147    @Override
148    public void setFaultCode(QName faultCodeQName) throws SOAPException {
149        setFaultCode(
150            faultCodeQName.getLocalPart(),
151            faultCodeQName.getPrefix(),
152            faultCodeQName.getNamespaceURI());
153    }
154
155    protected static QName convertCodeToQName(
156        String code,
157        SOAPElement codeContainingElement) {
158
159        int prefixIndex = code.indexOf(':');
160        if (prefixIndex == -1) {
161            return new QName(code);
162        }
163
164        String prefix = code.substring(0, prefixIndex);
165        String nsName =((ElementImpl) codeContainingElement).lookupNamespaceURI(prefix);
166            //((ElementImpl) codeContainingElement).getNamespaceURI(prefix);
167        return new QName(nsName, getLocalPart(code), prefix);
168    }
169
170    protected void initializeDetail() {
171        NameImpl detailName = getDetailName();
172        detail = (Detail) findAndConvertChildElement(detailName);
173    }
174
175    @Override
176    public Detail getDetail() {
177        if (detail == null)
178            initializeDetail();
179        if ((detail != null) && (detail.getParentNode() == null)) {
180        // a detach node was called on it
181            detail = null;
182        }
183        return detail;
184    }
185
186    @Override
187    public Detail addDetail() throws SOAPException {
188        if (detail == null)
189            initializeDetail();
190        if (detail == null) {
191            detail = createDetail();
192            addNode(detail);
193            return detail;
194        } else {
195            // Log
196            throw new SOAPExceptionImpl("Error: Detail already exists");
197        }
198    }
199
200    @Override
201    public boolean hasDetail() {
202        return (getDetail() != null);
203    }
204
205    @Override
206    public abstract void setFaultActor(String faultActor) throws SOAPException;
207
208    @Override
209    public String getFaultActor() {
210        if (this.faultActorElement == null)
211            findFaultActorElement();
212        if (this.faultActorElement != null) {
213                return this.faultActorElement.getValue();
214        }
215        return null;
216    }
217
218    @Override
219    public SOAPElement setElementQName(QName newName) throws SOAPException {
220
221        log.log(
222            Level.SEVERE,
223            "SAAJ0146.impl.invalid.name.change.requested",
224            new Object[] {elementQName.getLocalPart(), newName.getLocalPart()});
225        throw new SOAPException(
226            "Cannot change name for " + elementQName.getLocalPart() + " to " + newName.getLocalPart());
227    }
228
229    @Override
230    protected SOAPElement convertToSoapElement(Element element) {
231        final org.w3c.dom.Node soapNode = getSoapDocument().findIfPresent(element);
232        if (soapNode instanceof SOAPFaultElement) {
233            return (SOAPElement) soapNode;
234        } else if (soapNode instanceof SOAPElement) {
235            SOAPElement soapElement = (SOAPElement) soapNode;
236            if (getDetailName().equals(soapElement.getElementName())) {
237                return replaceElementWithSOAPElement(element, createDetail());
238            } else {
239                String localName =
240                    soapElement.getElementName().getLocalName();
241                if (isStandardFaultElement(localName))
242                    return replaceElementWithSOAPElement(
243                               element,
244                               createSOAPFaultElement(soapElement.getElementQName()));
245                return soapElement;
246            }
247        } else {
248            Name elementName = NameImpl.copyElementName(element);
249            ElementImpl newElement;
250            if (getDetailName().equals(elementName)) {
251                newElement = createDetail();
252            } else {
253                String localName = elementName.getLocalName();
254                if (isStandardFaultElement(localName))
255                    newElement =
256                        createSOAPFaultElement(elementName);
257                else
258                    newElement = (ElementImpl) createElement(elementName);
259            }
260            return replaceElementWithSOAPElement(element, newElement);
261        }
262    }
263
264    protected SOAPFaultElement addFaultCodeElement() throws SOAPException {
265        if (this.faultCodeElement == null)
266            findFaultCodeElement();
267        if (this.faultCodeElement == null) {
268            this.faultCodeElement =
269                addSOAPFaultElement(getFaultCodeName().getLocalName());
270            return this.faultCodeElement;
271        } else {
272            throw new SOAPExceptionImpl("Error: Faultcode already exists");
273        }
274    }
275
276    private SOAPFaultElement addFaultStringElement() throws SOAPException {
277        if (this.faultStringElement == null)
278            findFaultStringElement();
279        if (this.faultStringElement == null) {
280            this.faultStringElement =
281                addSOAPFaultElement(getFaultStringName().getLocalName());
282            return this.faultStringElement;
283        } else {
284            // Log
285            throw new SOAPExceptionImpl("Error: Faultstring already exists");
286        }
287    }
288
289    private SOAPFaultElement addFaultActorElement() throws SOAPException {
290        if (this.faultActorElement == null)
291            findFaultActorElement();
292        if (this.faultActorElement == null) {
293            this.faultActorElement =
294                addSOAPFaultElement(getFaultActorName().getLocalName());
295            return this.faultActorElement;
296        } else {
297            // Log
298            throw new SOAPExceptionImpl("Error: Faultactor already exists");
299        }
300    }
301
302    @Override
303    protected SOAPElement addElement(Name name) throws SOAPException {
304        if (getDetailName().equals(name)) {
305            return addDetail();
306        } else if(getFaultCodeName().equals(name)) {
307            return addFaultCodeElement();
308        } else if(getFaultStringName().equals(name)) {
309            return addFaultStringElement();
310        } else if(getFaultActorName().equals(name)) {
311            return addFaultActorElement();
312        }
313        return super.addElement(name);
314    }
315
316    @Override
317    protected SOAPElement addElement(QName name) throws SOAPException {
318        return addElement(NameImpl.convertToName(name));
319    }
320
321    protected FaultElementImpl addSOAPFaultElement(String localName)
322        throws SOAPException {
323
324        FaultElementImpl faultElem = createSOAPFaultElement(localName);
325        addNode(faultElem);
326        return faultElem;
327    }
328
329    /**
330     * Convert an xml:lang attribute value into a Locale object
331     * @param xmlLang xml:lang attribute value
332     * @return Locale
333     */
334    protected static Locale xmlLangToLocale(String xmlLang) {
335        if (xmlLang == null) {
336            return null;
337        }
338
339        // Spec uses hyphen as separator
340        int index = xmlLang.indexOf("-");
341
342        // Accept underscore as separator as well
343        if (index == -1) {
344            index = xmlLang.indexOf("_");
345        }
346
347        if (index == -1) {
348            // No separator so assume only a language component
349            return new Locale(xmlLang, "");
350        }
351
352        String language = xmlLang.substring(0, index);
353        String country = xmlLang.substring(index + 1);
354        return new Locale(language, country);
355    }
356
357    protected static String localeToXmlLang(Locale locale) {
358        String xmlLang = locale.getLanguage();
359        String country = locale.getCountry();
360        if (!"".equals(country)) {
361            xmlLang += "-" + country;
362        }
363        return xmlLang;
364    }
365}
366