Package org.apache.axis

Source Code of org.apache.axis.AxisFault

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.axis ;

import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.encoding.SerializationContext;
import org.apache.axis.message.SOAPEnvelope;
import org.apache.axis.message.SOAPFault;
import org.apache.axis.message.SOAPHeaderElement;
import org.apache.axis.soap.SOAPConstants;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.XMLUtils;
import org.apache.commons.logging.Log;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Text;

import javax.xml.namespace.QName;
import javax.xml.parsers.ParserConfigurationException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;

/**
* An exception which maps cleanly to a SOAP fault.
* This is a base class for exceptions which are mapped to faults.
* SOAP faults contain
* <ol>
* <li>A fault string
* <li>A fault code
* <li>A fault actor
* <li>Fault details; an xml tree of fault specific stuff
* </ol>
* @author Doug Davis (dug@us.ibm.com)
* @author James Snell (jasnell@us.ibm.com)
* @author Steve Loughran
*/

public class AxisFault extends java.rmi.RemoteException {
    protected static Log log =
        LogFactory.getLog(AxisFault.class.getName());

    protected QName     faultCode ;
    /** SOAP1.2 addition: subcodes of faults; a Vector of QNames */
    protected Vector    faultSubCode ;
    protected String    faultString = "";
    protected String    faultActor ;
    protected Vector    faultDetails ;  // vector of Element's
    protected String    faultNode ;

    /** SOAP headers which should be serialized with the Fault */
    protected ArrayList faultHeaders = null;

    /**
     * Make an AxisFault based on a passed Exception.  If the Exception is
     * already an AxisFault, simply use that.  Otherwise, wrap it in an
     * AxisFault.  If the Exception is an InvocationTargetException (which
     * already wraps another Exception), get the wrapped Exception out from
     * there and use that instead of the passed one.
     */
    public static AxisFault makeFault(Exception e)
    {
        if (e instanceof InvocationTargetException) {
            Throwable t = ((InvocationTargetException)e).getTargetException();
            if (t instanceof Exception) {
                e = (Exception)t;
            }
        }
       
        if (e instanceof AxisFault) {
            return (AxisFault)e;
        }
       
        return new AxisFault(e);
    }

    /**
     * make a fault
     * @param code fault code which will be passed into the Axis namespace
     * @param faultString fault string
     * @param actor fault actor
     * @param details details; if null the current stack trace and classname is
     * inserted into the details.
     */
    public AxisFault(String code, String faultString,
                     String actor, Element[] details) {
        this(new QName(Constants.NS_URI_AXIS, code),
                faultString, actor, details);
    }

    /**
     * make a fault in any namespace
     * @param code fault code which will be passed into the Axis namespace
     * @param faultString fault string
     * @param actor fault actor
     * @param details details; if null the current stack trace and classname is
     * inserted into the details.
     */
    public AxisFault(QName code, String faultString,
                     String actor, Element[] details) {
        super (faultString);
        setFaultCode( code );
        setFaultString( faultString );
        setFaultActor( actor );
        setFaultDetail( details );
        if (details == null) {
            initFromException(this);
        }
    }

    /**
     * make a fault in any namespace
     * @param code fault code which will be passed into the Axis namespace
     * @param subcodes fault subcodes which will be pased into the Axis namespace
     * @param faultString fault string
     * @param actor fault actor, same as fault role in SOAP 1.2
     * @param node which node caused the fault on the SOAP path
     * @param details details; if null the current stack trace and classname is
     * inserted into the details.
     * @since axis1.1
     */
    public AxisFault(QName code, QName[] subcodes, String faultString,
                     String actor, String node, Element[] details) {
        super (faultString);
        setFaultCode( code );
        if (subcodes != null) {
            for (int i = 0; i < subcodes.length; i++) {
                addFaultSubCode( subcodes[i] );
            }
        }
        setFaultString( faultString );
        setFaultActor( actor );
        setFaultNode( node );
        setFaultDetail( details );
        if (details == null) {
            initFromException(this);
        }
    }

    /**
     * Wrap an AxisFault around an existing Exception - this is private
     * to force everyone to use makeFault() above, which sanity-checks us.
     */
    protected AxisFault(Exception target) {
        super ("", target);
        // ? SOAP 1.2 or 1.1 ?
        setFaultCodeAsString( Constants.FAULT_SERVER_USER );
       
        initFromException(target);
    }

    /**
     * create a simple axis fault from the message. Classname and stack trace
     * go into the fault details.
     * @param message
     */
    public AxisFault(String message)
    {
        super (message);
        setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
        setFaultString(message);
        initFromException(this);
    }

    /**
     * No-arg constructor for building one from an XML stream.
     */
    public AxisFault()
    {
        super();
        setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);    
        initFromException(this);
    }

    /**
     * create a fault from any throwable;
     * When faulting a throwable (as opposed to an exception),
     * stack trace information does not go into the fault.
     * @param message any extra text to with the fault
     * @param t whatever is to be turned into a fault
     */
    public AxisFault (String message, Throwable t)
    {
        super (message, t);
        setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
        setFaultString(getMessage());
    }

    /**
     * fill in soap fault details from the exception, unless
     * this object already has a stack trace in its details. Which, given
     * the way this private method is invoked, is a pretty hard situation to ever achieve.
     * This method adds classname of the exception and the stack trace.
     * @param target what went wrong
     */
    private void initFromException(Exception target)
    {
        //look for old stack trace
        Element oldStackTrace=lookupFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE);
        if(oldStackTrace!=null) {
            // todo: Should we replace it or just let it be?
            return;
        }

        // Set the exception message (if any) as the fault string
        setFaultString( target.toString() );


        // If we're derived from AxisFault, then put the exception class
        // into the "exceptionName" element in the details.  This allows
        // us to get back a correct Java Exception class on the other side
        // (assuming they have it available).
       
        if ((target instanceof AxisFault) &&
            (target.getClass() != AxisFault.class)) {
            addFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME,
                    target.getClass().getName());
        }
        //add stack trace
        addFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE,
                JavaUtils.stackToString(target));


    }

    /**
     * init the fault details data structure; does nothing
     * if this exists already
     */
    private void initFaultDetails() {
        if (faultDetails == null) {
            faultDetails = new Vector();
        }
    }

    /**
     * clear the fault details list
     */
    public void clearFaultDetails() {
        faultDetails=null;
    }

    /**
     * dump the fault info to the log at debug level
     */
    public void dump()
    {
        log.debug(dumpToString());
    }


    /**
     * turn the fault and details into a string, with XML escaping.
     * subclassers: for security (cross-site-scripting) reasons,
     * escape everything that could contain caller-supplied data.
     * @return stringified fault details
     */
    public String dumpToString()
    {
        String details = new String();

        if (faultDetails != null) {
            for (int i=0; i < faultDetails.size(); i++) {
                Element e = (Element) faultDetails.get(i);
                String namespace= e.getNamespaceURI();
                if(namespace==null) {
                    namespace="";
                }
                String partname= e.getLocalName();
                if(partname==null) {
                    partname=e.getNodeName();
                }
                details += JavaUtils.LS
                          + "\t{" + namespace + "}"
                          + partname + ": "
                          + XMLUtils.getInnerXMLString(e);
            }
        }

        String subCodes = new String();
        if (faultSubCode != null) {
            for (int i = 0; i < faultSubCode.size(); i++) {
                subCodes += JavaUtils.LS
                            + (QName)faultSubCode.elementAt(i);
            }
        }
        //encode everything except details and subcodes, which are already
        //dealt with one way or another.
        String code= XMLUtils.xmlEncodeString(faultCode.toString());
        String errorString= XMLUtils.xmlEncodeString(faultString);
        String actor= XMLUtils.xmlEncodeString(faultActor);
        String node= XMLUtils.xmlEncodeString(faultNode);


        return "AxisFault" + JavaUtils.LS
            + " faultCode: " + code + JavaUtils.LS
            + " faultSubcode: " + subCodes + JavaUtils.LS
            + " faultString: " + errorString + JavaUtils.LS
            + " faultActor: " + actor + JavaUtils.LS
            + " faultNode: " + node + JavaUtils.LS
            + " faultDetail: " + details + JavaUtils.LS
            ;
    }

    /**
     * set the fault code
     * @param code a new fault code
     */
    public void setFaultCode(QName code) {
        faultCode = code ;
    }
   
    /**
     * Set the fault code (as a String).
     *
     * @deprecated expect to see this go away after 1.1, use
     *             setFaultCodeAsString instead!
     */

    public void setFaultCode(String code) {
        setFaultCodeAsString(code);
    }
   
    /**
     * set a fault code string that is turned into a qname
     * in the SOAP 1.1 or 1.2 namespace, depending on the current context
     * @param code fault code
     */
    public void setFaultCodeAsString(String code) {
        SOAPConstants soapConstants = MessageContext.getCurrentContext() == null ?
                                        SOAPConstants.SOAP11_CONSTANTS :
                                        MessageContext.getCurrentContext().getSOAPConstants();
       
        faultCode = new QName(soapConstants.getEnvelopeURI(), code);
    }

    /**
     * get the fault code
     * @return fault code QName or null if there is none yet.
     */
    public QName getFaultCode() {
        return( faultCode );
    }

    /**
     * This is new in SOAP 1.2, ignored in SOAP 1.1
     * @since axis1.1
     */
    public void addFaultSubCodeAsString(String code) {
        initFaultSubCodes();
        faultSubCode.add(new QName(Constants.NS_URI_AXIS, code));
    }

    /**
     * do whatever is needed to create the fault subcodes
     * data structure, if it is needed
     */
    protected void initFaultSubCodes() {
        if (faultSubCode == null) {
            faultSubCode = new Vector();
        }
    }

    /**
     * This is new in SOAP 1.2, ignored in SOAP 1.1
     * @since axis1.1
     */
    public void addFaultSubCode(QName code) {
        initFaultSubCodes();
        faultSubCode.add(code);
    }

    /**
     * This is new in SOAP 1.2, ignored in SOAP 1.1
     *
     * @since axis1.1
     */
    public void clearFaultSubCodes() {
        faultSubCode = null;
    }

    /**
     * get the fault subcode list; only used in SOAP 1.2
     * @since axis1.1
     * @return null for no subcodes, or a QName array
     */
    public QName[] getFaultSubCodes() {
        if (faultSubCode == null) {
            return null;
        }
        QName[] q = new QName[faultSubCode.size()];
        return (QName[])faultSubCode.toArray(q);
    }


    /**
     * set a fault string;
     * @param str new fault string; null is turned into ""
     */
    public void setFaultString(String str) {
        if (str != null) {
            faultString = str ;
        } else {
            faultString = "";
        }
    }

    /**
     * get the fault string; this will never be null but may be the
     * empty string
     * @return a fault string
     */
    public String getFaultString() {
        return( faultString );
    }

    /**
     * This is SOAP 1.2 equivalent of {@link #setFaultString(java.lang.String)}
     * @since axis1.1
     */
    public void setFaultReason(String str) {
        setFaultString(str);
    }

    /**
     * This is SOAP 1.2 equivalent of {@link #getFaultString()}
     * @since axis1.1
     * @return
     */
    public String getFaultReason() {
        return getFaultString();
    }

    /**
     * set the fault actor
     * @param actor fault actor
     */
    public void setFaultActor(String actor) {
        faultActor = actor ;
    }

    /**
     * get the fault actor
     * @return actor or null
     */
    public String getFaultActor() {
        return( faultActor );
    }

    /**
     * This is SOAP 1.2 equivalent of {@link #getFaultActor()}
     * @since axis1.1
     * @return
     */
    public String getFaultRole() {
        return getFaultActor();
    }

    /**
     * This is SOAP 1.2 equivalent of {@link #setFaultActor(java.lang.String)}
     * @since axis1.1
     */
    public void setFaultRole(String role) {
        setFaultActor(role);
    }

    /**
     * This is new in SOAP 1.2
     * @since axis1.1
     * @return
     */
    public String getFaultNode() {
        return( faultNode );
    }

    /**
     * This is new in SOAP 1.2
     * @since axis1.1
     */
    public void setFaultNode(String node) {
        faultNode = node;
    }

    /**
     * set the fault detail element to the arrary of details
     * @param details list of detail elements, can be null
     */
    public void setFaultDetail(Element[] details) {
        if ( details == null ) {
            faultDetails=null;
            return ;
        }
        faultDetails = new Vector( details.length );
        for ( int loop = 0 ; loop < details.length ; loop++ ) {
            faultDetails.add( details[loop] );
        }
    }

    /**
     * set the fault details to a string element.
     * @param details XML fragment
     */
    public void setFaultDetailString(String details) {
        clearFaultDetails();
        addFaultDetailString(details);
    }

    /**
     * add a string tag to the fault details.
     * @param detail XML fragment
     */
    public void addFaultDetailString(String detail) {
        initFaultDetails();
        try {
            Document doc = XMLUtils.newDocument();
            Element element = doc.createElement("string");
            Text text = doc.createTextNode(detail);
            element.appendChild(text);
            faultDetails.add(element);
        } catch (ParserConfigurationException e) {
            // This should not occur
            throw new InternalException(e);
        }
    }

    /**
     * append an element to the fault detail list
     * @param detail the new element to add
     * @since Axis1.1
     */
    public void addFaultDetail(Element detail) {
        initFaultDetails();
        faultDetails.add(detail);
    }

    /**
     * create an element of the given qname and add it to the details
     * @param qname qname of the element
     * @param body string to use as body
     */
    public void addFaultDetail(QName qname,String body) {
        Element detail = XMLUtils.StringToElement(qname.getNamespaceURI(),
                qname.getLocalPart(),
                body);

        addFaultDetail(detail);
    }
    /**
     * get all the fault details
     * @return an array of fault details, or null for none
     */
    public Element[] getFaultDetails() {
        if (faultDetails == null) {
            return null;
        }
        Element result[] = new Element[faultDetails.size()];
        for (int i=0; i<result.length; i++)
            result[i] = (Element) faultDetails.elementAt(i);
        return result;
    }

    /**
     * Find a fault detail element by its qname
     * @param qname name of the node to look for
     * @return the matching element or null
     * @since axis1.1
     */
    public Element lookupFaultDetail(QName qname) {
        if (faultDetails != null) {
            //extract details from the qname. the empty namespace is represented
            //by the empty string
            String searchNamespace = qname.getNamespaceURI();
            String searchLocalpart = qname.getLocalPart();
            //now spin through the elements, seeking a match
            Iterator it=faultDetails.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String localpart= e.getLocalName();
                if(localpart==null) {
                    localpart=e.getNodeName();
                }
                String namespace= e.getNamespaceURI();
                if(namespace==null) {
                    namespace="";
                }
                //we match on matching namespace and local part; empty namespace
                //in an element may be null, which matches QName's ""
                if(searchNamespace.equals(namespace)
                    && searchLocalpart.equals(localpart)) {
                    return e;
                }
            }
        }
        return null;
    }

    /**
     * find and remove a specified fault detail element
     * @param qname qualified name of detail
     * @return true if it was found and removed
     * @since axis1.1
     */
    public boolean removeFaultDetail(QName qname) {
        Element elt=lookupFaultDetail(qname);
        if(elt==null) {
            return false;
        } else {
            return faultDetails.remove(elt);
        }
    }

    /**
     * add this fault and any needed headers to the output context
     * @param context
     * @throws Exception
     */
    public void output(SerializationContext context) throws Exception {

        SOAPConstants soapConstants = Constants.DEFAULT_SOAP_VERSION;
        if (context.getMessageContext() != null)
            soapConstants = context.getMessageContext().getSOAPConstants();

        SOAPEnvelope envelope = new SOAPEnvelope(soapConstants);

        SOAPFault fault = new SOAPFault(this);
        envelope.addBodyElement(fault);

        // add any headers we need
        if (faultHeaders != null) {
            for (Iterator i = faultHeaders.iterator(); i.hasNext();) {
                SOAPHeaderElement header = (SOAPHeaderElement) i.next();
                envelope.addHeader(header);
            }
        }

        envelope.output(context);
    }

    /**
     * string operator
     * @return the current fault string; may be empty but never null
     */
    public String toString() {
        return faultString;
    }

    /**
     * The override of the base class method prints out the
     * fault info before the stack trace
     * @param ps where to print
     */
    public void printStackTrace(PrintStream ps) {
        ps.println(dumpToString());
        super.printStackTrace(ps);
    }

    /**
     * The override of the base class method prints out the
     * fault info before the stack trace
     * @param pw where to print
     */
    public void printStackTrace(java.io.PrintWriter pw) {
        pw.println(dumpToString());
        super.printStackTrace(pw);
    }

    /**
     * Add a SOAP header which should be serialized along with the
     * fault.
     *
     * @param header a SOAPHeaderElement containing some fault-relevant stuff
     */
    public void addHeader(SOAPHeaderElement header) {
        if (faultHeaders == null) {
            faultHeaders = new ArrayList();
        }
        faultHeaders.add(header);
    }
   
    /**
     * Get the SOAP headers associated with this fault.
     *
     * @return an ArrayList containing any headers associated with this fault
     */
    public ArrayList getHeaders() {
        return faultHeaders;
    }

    /**
     * clear all fault headers
     */
    public void clearHeaders() {
        faultHeaders = null;
    }
   
    /**
     *  Writes any exception data to the faultDetails
     * This is for overriding; it is empty in the base AxisFault
     */
    public void writeDetails(QName qname, SerializationContext context) throws java.io.IOException {
        // no data in default Axis fault
    }

};
TOP

Related Classes of org.apache.axis.AxisFault

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.