📄 axisfault.java
字号:
/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.axis ;import java.io.PrintStream;import java.lang.reflect.InvocationTargetException;import java.util.ArrayList;import java.util.Iterator;import java.util.Vector;import java.io.PrintWriter;import java.io.StringWriter;import javax.xml.namespace.QName;import javax.xml.parsers.ParserConfigurationException;import javax.xml.rpc.soap.SOAPFaultException;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.axis.utils.NetworkUtils;import org.apache.commons.logging.Log;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Text;/** * 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 { /** * The <code>Log</code> used by this class for all logging. */ 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. * * @param e the <code>Exception</code> to build a fault for * @return an <code>AxisFault</code> representing <code>e</code> */ 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 in the <code>Constants.NS_URI_AXIS</code> 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(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); } } // fixme: docs says private, access says protected /** * Wrap an AxisFault around an existing Exception. This is private * to force everyone to use makeFault() above, which sanity-checks us. * * @param target the target <code>Exception</code> */ protected AxisFault(Exception target) { super ("", target); // ? SOAP 1.2 or 1.1 ? setFaultCodeAsString( Constants.FAULT_SERVER_USER ); initFromException(target); // if the target is a JAX-RPC SOAPFaultException init // AxisFault with the values from the SOAPFaultException if ( target instanceof SOAPFaultException ) { //strip out the hostname as we want any new one removeHostname(); initFromSOAPFaultException((SOAPFaultException) target); //but if they left it out, add it addHostnameIfNeeded(); } } /** * 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()); addHostnameIfNeeded(); } /** * 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() ); // Put the exception class into the AXIS SPECIFIC HACK // "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). // NOTE: This hack is obsolete! We now serialize exception data // and the other side uses *that* QName to figure out what exception // to use, because the class name may be completly different on the // client. if ((target instanceof AxisFault) && (target.getClass() != AxisFault.class)) { addFaultDetail(Constants.QNAME_FAULTDETAIL_EXCEPTIONNAME, target.getClass().getName()); } //add stack trace if (target == this) { // only add stack trace. JavaUtils.stackToString() call would // include dumpToString() info which is already sent as different // elements of this fault. addFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE, getPlainStackTrace()); } else { addFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE, JavaUtils.stackToString(target)); } //add the hostname addHostnameIfNeeded(); } /** * Initiates the AxisFault with the values from a SOAPFaultException * @param fault SOAPFaultException */ private void initFromSOAPFaultException(SOAPFaultException fault) { // faultcode if ( fault.getFaultCode() != null ) { setFaultCode(fault.getFaultCode()); } // faultstring if ( fault.getFaultString() != null ) { setFaultString(fault.getFaultString()); } // actor if ( fault.getFaultActor() != null ) { setFaultActor(fault.getFaultActor()); } if ( null == fault.getDetail() ) { return; } // We get an Iterator but we need a List Vector details = new Vector(); Iterator detailIter = fault.getDetail().getChildElements(); while (detailIter.hasNext()) { details.add( detailIter.next()); } // Convert the List in an Array an return the array setFaultDetail( XMLUtils.asElementArray(details)); } /** * 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() { StringBuffer buf = new StringBuffer("AxisFault"); buf.append(JavaUtils.LS); buf.append(" faultCode: "); buf.append(XMLUtils.xmlEncodeString(faultCode.toString())); buf.append(JavaUtils.LS); buf.append(" faultSubcode: "); if (faultSubCode != null) { for (int i = 0; i < faultSubCode.size(); i++) { buf.append(JavaUtils.LS); buf.append(faultSubCode.elementAt(i).toString()); } } buf.append(JavaUtils.LS); buf.append(" faultString: "); try { buf.append(XMLUtils.xmlEncodeString(faultString)); } catch (RuntimeException re) { buf.append(re.getMessage()); } buf.append(JavaUtils.LS); buf.append(" faultActor: "); buf.append(XMLUtils.xmlEncodeString(faultActor)); buf.append(JavaUtils.LS); buf.append(" faultNode: "); buf.append(XMLUtils.xmlEncodeString(faultNode)); buf.append(JavaUtils.LS); buf.append(" faultDetail: "); if (faultDetails != null) { for (int i=0; i < faultDetails.size(); i++) { Element e = (Element) faultDetails.get(i); buf.append(JavaUtils.LS); buf.append("\t{"); buf.append(null == e.getNamespaceURI() ? "" : e.getNamespaceURI()); buf.append("}"); buf.append(null == e.getLocalName() ? "" : e.getLocalName()); buf.append(":"); buf.append(XMLUtils.getInnerXMLString(e)); } } buf.append(JavaUtils.LS); return buf.toString(); } /** * Set the fault code. * * @param code a new fault code */ public void setFaultCode(QName code) { faultCode = code ; } /** * Set the fault code (as a String). * * @param code a new fault code * @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 <code>QName</code>. * * @return fault code QName or null if there is none yet. */ public QName getFaultCode() { return( faultCode ); } /** * Add a fault sub-code with the local name <code>code</code> and namespace * <code>Constants.NS_URI_AXIS</code>. * This is new in SOAP 1.2, ignored in SOAP 1.1 * * @param code the local name of the code to add * @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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -