KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > axis > AxisFault


1 /*
2  * Copyright (C) The Apache Software Foundation. All rights reserved.
3  *
4  * This software is published under the terms of the Apache Software License
5  * version 1.1, a copy of which has been included with this distribution in
6  * the docs/licenses/apache-1.1.txt file.
7  */

8
9 package org.jboss.axis;
10
11 import org.jboss.axis.encoding.SerializationContext;
12 import org.jboss.axis.encoding.Serializer;
13 import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
14 import org.jboss.axis.message.SOAPFaultImpl;
15 import org.jboss.axis.message.SOAPHeaderElementAxisImpl;
16 import org.jboss.axis.soap.SOAPConstants;
17 import org.jboss.axis.utils.JavaUtils;
18 import org.jboss.axis.utils.XMLUtils;
19 import org.jboss.logging.Logger;
20 import org.w3c.dom.Document JavaDoc;
21 import org.w3c.dom.Element JavaDoc;
22 import org.w3c.dom.Text JavaDoc;
23
24 import javax.xml.namespace.QName JavaDoc;
25 import javax.xml.parsers.ParserConfigurationException JavaDoc;
26 import javax.xml.rpc.JAXRPCException JavaDoc;
27 import java.io.PrintStream JavaDoc;
28 import java.lang.reflect.InvocationTargetException JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Vector JavaDoc;
32
33 /**
34  * An exception which maps cleanly to a SOAP fault.
35  * This is a base class for exceptions which are mapped to faults.
36  * SOAP faults contain
37  * <ol>
38  * <li>A fault string
39  * <li>A fault code
40  * <li>A fault actor
41  * <li>Fault details; an xml tree of fault specific stuff
42  * </ol>
43  *
44  * @author Doug Davis (dug@us.ibm.com)
45  * @author James Snell (jasnell@us.ibm.com)
46  * @author Steve Loughran
47  */

48
49 public class AxisFault extends java.rmi.RemoteException JavaDoc
50 {
51
52    private static Logger log = Logger.getLogger(AxisFault.class.getName());
53
54    protected QName JavaDoc faultCode;
55    /**
56     * SOAP1.2 addition: subcodes of faults; a Vector of QNames
57     */

58    protected Vector JavaDoc faultSubCode;
59    protected String JavaDoc faultString = "";
60    protected String JavaDoc faultActor;
61    protected Vector JavaDoc faultDetails; // vector of Element's
62
protected String JavaDoc faultNode;
63
64    /** SOAP headers which should be serialized with the Fault
65     * List<SOAPHeaderElementAxisImpl>
66     */

67    protected ArrayList JavaDoc faultHeaders;
68
69    /**
70     * Make an AxisFault based on a passed Exception. If the Exception is
71     * already an AxisFault, simply use that. Otherwise, wrap it in an
72     * AxisFault. If the Exception is an InvocationTargetException (which
73     * already wraps another Exception), get the wrapped Exception out from
74     * there and use that instead of the passed one.
75     */

76    public static AxisFault makeFault(Exception JavaDoc e)
77    {
78       if (e instanceof InvocationTargetException JavaDoc)
79       {
80          InvocationTargetException JavaDoc ite = (InvocationTargetException JavaDoc)e;
81          Throwable JavaDoc t = ite.getTargetException();
82          if (t instanceof Exception JavaDoc)
83             e = (Exception JavaDoc)t;
84       }
85
86       if (e instanceof JAXRPCException JavaDoc)
87       {
88          JAXRPCException JavaDoc rte = (JAXRPCException JavaDoc)e;
89          Throwable JavaDoc t = rte.getLinkedCause();
90          if (t instanceof Exception JavaDoc)
91             e = (Exception JavaDoc)t;
92       }
93
94       if (e instanceof AxisFault)
95       {
96          return (AxisFault)e;
97       }
98
99       return new AxisFault(e);
100    }
101
102    /**
103     * make a fault
104     *
105     * @param code fault code which will be passed into the Axis namespace
106     * @param faultString fault string
107     * @param actor fault actor
108     * @param details details; if null the current stack trace and classname is
109     * inserted into the details.
110     */

111    public AxisFault(String JavaDoc code, String JavaDoc faultString, String JavaDoc actor, Element JavaDoc[] details)
112    {
113       this(new QName JavaDoc(Constants.NS_URI_AXIS, code),
114               faultString, actor, details);
115    }
116
117    /**
118     * make a fault in any namespace
119     *
120     * @param code fault code which will be passed into the Axis namespace
121     * @param faultString fault string
122     * @param actor fault actor
123     * @param details details; if null the current stack trace and classname is
124     * inserted into the details.
125     */

126    public AxisFault(QName JavaDoc code, String JavaDoc faultString, String JavaDoc actor, Element JavaDoc[] details)
127    {
128       super(faultString);
129       setFaultCode(code);
130       setFaultString(faultString);
131       setFaultActor(actor);
132       setFaultDetail(details);
133    }
134
135    /**
136     * make a fault in any namespace
137     *
138     * @param code fault code which will be passed into the Axis namespace
139     * @param subcodes fault subcodes which will be pased into the Axis namespace
140     * @param faultString fault string
141     * @param actor fault actor, same as fault role in SOAP 1.2
142     * @param node which node caused the fault on the SOAP path
143     * @param details details; if null the current stack trace and classname is
144     * inserted into the details.
145     * @since axis1.1
146     */

147    public AxisFault(QName JavaDoc code, QName JavaDoc[] subcodes, String JavaDoc faultString,
148                     String JavaDoc actor, String JavaDoc node, Element JavaDoc[] details)
149    {
150       super(faultString);
151       setFaultCode(code);
152       if (subcodes != null)
153       {
154          for (int i = 0; i < subcodes.length; i++)
155          {
156             addFaultSubCode(subcodes[i]);
157          }
158       }
159       setFaultString(faultString);
160       setFaultActor(actor);
161       setFaultNode(node);
162       setFaultDetail(details);
163    }
164
165    /**
166     * Wrap an AxisFault around an existing Exception - this is private
167     * to force everyone to use makeFault() above, which sanity-checks us.
168     */

169    protected AxisFault(Exception JavaDoc target)
170    {
171       super(target.getMessage(), assertTarget(target));
172       // ? SOAP 1.2 or 1.1 ?
173
setFaultCodeAsString(Constants.FAULT_SERVER_USER);
174       initFromException(target);
175    }
176
177    /**
178     * Check for nested AxisFault
179     * [todo] TDI 07-June-2004
180     */

181    private static Throwable JavaDoc assertTarget(Throwable JavaDoc target)
182    {
183 // if (target instanceof AxisFault)
184
// log.warn("Nested AxisFault detected", new IllegalArgumentException());
185
return target;
186    }
187
188    /**
189     * create a simple axis fault from the message. Classname and stack trace
190     * go into the fault details.
191     *
192     * @param message
193     */

194    public AxisFault(String JavaDoc message)
195    {
196       super(message);
197       setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
198       setFaultString(message);
199    }
200
201    /**
202     * No-arg constructor for building one from an XML stream.
203     */

204    public AxisFault()
205    {
206       super();
207       setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
208    }
209
210    /**
211     * create a fault from any throwable;
212     * When faulting a throwable (as opposed to an exception),
213     * stack trace information does not go into the fault.
214     *
215     * @param message any extra text to with the fault
216     * @param target whatever is to be turned into a fault
217     */

218    public AxisFault(String JavaDoc message, Throwable JavaDoc target)
219    {
220       super(message, assertTarget(target));
221       setFaultCodeAsString(Constants.FAULT_SERVER_GENERAL);
222       setFaultString(getMessage());
223    }
224
225    /**
226     * fill in soap fault details from the exception, unless
227     * this object already has a stack trace in its details. Which, given
228     * the way this private method is invoked, is a pretty hard situation to ever achieve.
229     * This method adds classname of the exception and the stack trace.
230     *
231     * @param target what went wrong
232     */

233    private void initFromException(Exception JavaDoc target)
234    {
235       assertTarget(target);
236
237       // Set the exception message (if any) as the fault string
238
String JavaDoc faultString = target.getMessage();
239       setFaultString(faultString != null ? faultString : target.toString());
240
241       Throwable JavaDoc cause = target;
242       if (target instanceof AxisFault)
243          cause = ((AxisFault)target).detail;
244
245       // Add the stack trace as detail element
246
if (cause != null)
247       {
248          //add stack trace
249
addFaultDetail(Constants.QNAME_FAULTDETAIL_STACKTRACE, JavaUtils.stackToString(cause));
250       }
251    }
252
253    /**
254     * init the fault details data structure; does nothing
255     * if this exists already
256     */

257    private void initFaultDetails()
258    {
259       if (faultDetails == null)
260       {
261          faultDetails = new Vector JavaDoc();
262       }
263    }
264
265    /**
266     * clear the fault details list
267     */

268    public void clearFaultDetails()
269    {
270       faultDetails = null;
271    }
272
273    /**
274     * dump the fault info to the log at debug level
275     */

276    public void dump()
277    {
278       log.debug(dumpToString());
279    }
280
281
282    /**
283     * turn the fault and details into a string, with XML escaping.
284     * subclassers: for security (cross-site-scripting) reasons,
285     * escape everything that could contain caller-supplied data.
286     *
287     * @return stringified fault details
288     */

289    public String JavaDoc dumpToString()
290    {
291       String JavaDoc details = new String JavaDoc();
292
293       if (faultDetails != null)
294       {
295          for (int i = 0; i < faultDetails.size(); i++)
296          {
297             Element JavaDoc e = (Element JavaDoc)faultDetails.get(i);
298             String JavaDoc namespace = e.getNamespaceURI();
299             if (namespace == null)
300             {
301                namespace = "";
302             }
303             String JavaDoc partname = e.getLocalName();
304             if (partname == null)
305             {
306                partname = e.getNodeName();
307             }
308             details += JavaUtils.LS
309                     + "\t{" + namespace + "}"
310                     + partname + ": "
311                     + XMLUtils.getInnerXMLString(e);
312          }
313       }
314
315       String JavaDoc subCodes = new String JavaDoc();
316       if (faultSubCode != null)
317       {
318          for (int i = 0; i < faultSubCode.size(); i++)
319          {
320             subCodes += JavaUtils.LS
321                     + (QName JavaDoc)faultSubCode.elementAt(i);
322          }
323       }
324       //encode everything except details and subcodes, which are already
325
//dealt with one way or another.
326
String JavaDoc code = XMLUtils.xmlEncodeString(faultCode.toString());
327       String JavaDoc errorString = XMLUtils.xmlEncodeString(faultString);
328       String JavaDoc actor = XMLUtils.xmlEncodeString(faultActor);
329       String JavaDoc node = XMLUtils.xmlEncodeString(faultNode);
330
331
332       return "AxisFault" + JavaUtils.LS
333               + " faultCode: " + code + JavaUtils.LS
334               + " faultSubcode: " + subCodes + JavaUtils.LS
335               + " faultString: " + errorString + JavaUtils.LS
336               + " faultActor: " + actor + JavaUtils.LS
337               + " faultNode: " + node + JavaUtils.LS
338               + " faultDetail: " + details + JavaUtils.LS
339               ;
340    }
341
342    /**
343     * set the fault code
344     *
345     * @param code a new fault code
346     */

347    public void setFaultCode(QName JavaDoc code)
348    {
349       faultCode = code;
350    }
351
352    /**
353     * Set the fault code (as a String).
354     *
355     * @deprecated expect to see this go away after 1.1, use
356     * setFaultCodeAsString instead!
357     */

358
359    public void setFaultCode(String JavaDoc code)
360    {
361       setFaultCodeAsString(code);
362    }
363
364    /**
365     * set a fault code string that is turned into a qname
366     * in the SOAP 1.1 or 1.2 namespace, depending on the current context
367     *
368     * @param code fault code
369     */

370    public void setFaultCodeAsString(String JavaDoc code)
371    {
372       SOAPConstants soapConstants = MessageContext.getCurrentContext() == null ?
373               SOAPConstants.SOAP11_CONSTANTS :
374               MessageContext.getCurrentContext().getSOAPConstants();
375
376       faultCode = new QName JavaDoc(soapConstants.getEnvelopeURI(), code);
377    }
378
379    /**
380     * get the fault code
381     *
382     * @return fault code QName or null if there is none yet.
383     */

384    public QName JavaDoc getFaultCode()
385    {
386       return (faultCode);
387    }
388
389    /**
390     * This is new in SOAP 1.2, ignored in SOAP 1.1
391     *
392     * @since axis1.1
393     */

394    public void addFaultSubCodeAsString(String JavaDoc code)
395    {
396       initFaultSubCodes();
397       faultSubCode.add(new QName JavaDoc(Constants.NS_URI_AXIS, code));
398    }
399
400    /**
401     * do whatever is needed to create the fault subcodes
402     * data structure, if it is needed
403     */

404    protected void initFaultSubCodes()
405    {
406       if (faultSubCode == null)
407       {
408          faultSubCode = new Vector JavaDoc();
409       }
410    }
411
412    /**
413     * This is new in SOAP 1.2, ignored in SOAP 1.1
414     *
415     * @since axis1.1
416     */

417    public void addFaultSubCode(QName JavaDoc code)
418    {
419       initFaultSubCodes();
420       faultSubCode.add(code);
421    }
422
423    /**
424     * This is new in SOAP 1.2, ignored in SOAP 1.1
425     *
426     * @since axis1.1
427     */

428    public void clearFaultSubCodes()
429    {
430       faultSubCode = null;
431    }
432
433    /**
434     * get the fault subcode list; only used in SOAP 1.2
435     *
436     * @return null for no subcodes, or a QName array
437     * @since axis1.1
438     */

439    public QName JavaDoc[] getFaultSubCodes()
440    {
441       if (faultSubCode == null)
442       {
443          return null;
444       }
445       QName JavaDoc[] q = new QName JavaDoc[faultSubCode.size()];
446       return (QName JavaDoc[])faultSubCode.toArray(q);
447    }
448
449
450    /**
451     * set a fault string;
452     *
453     * @param str new fault string; null is turned into ""
454     */

455    public void setFaultString(String JavaDoc str)
456    {
457       if (str != null)
458       {
459          faultString = str;
460       }
461       else
462       {
463          faultString = "";
464       }
465    }
466
467    /**
468     * get the fault string; this will never be null but may be the
469     * empty string
470     *
471     * @return a fault string
472     */

473    public String JavaDoc getFaultString()
474    {
475       return (faultString);
476    }
477
478    /**
479     * This is SOAP 1.2 equivalent of {@link #setFaultString(java.lang.String)}
480     *
481     * @since axis1.1
482     */

483    public void setFaultReason(String JavaDoc str)
484    {
485       setFaultString(str);
486    }
487
488    /**
489     * This is SOAP 1.2 equivalent of {@link #getFaultString()}
490     *
491     * @return
492     * @since axis1.1
493     */

494    public String JavaDoc getFaultReason()
495    {
496       return getFaultString();
497    }
498
499    /**
500     * set the fault actor
501     *
502     * @param actor fault actor
503     */

504    public void setFaultActor(String JavaDoc actor)
505    {
506       faultActor = actor;
507    }
508
509    /**
510     * get the fault actor
511     *
512     * @return actor or null
513     */

514    public String JavaDoc getFaultActor()
515    {
516       return (faultActor);
517    }
518
519    /**
520     * This is SOAP 1.2 equivalent of {@link #getFaultActor()}
521     *
522     * @return
523     * @since axis1.1
524     */

525    public String JavaDoc getFaultRole()
526    {
527       return getFaultActor();
528    }
529
530    /**
531     * This is SOAP 1.2 equivalent of {@link #setFaultActor(java.lang.String)}
532     *
533     * @since axis1.1
534     */

535    public void setFaultRole(String JavaDoc role)
536    {
537       setFaultActor(role);
538    }
539
540    /**
541     * This is new in SOAP 1.2
542     *
543     * @return
544     * @since axis1.1
545     */

546    public String JavaDoc getFaultNode()
547    {
548       return (faultNode);
549    }
550
551    /**
552     * This is new in SOAP 1.2
553     *
554     * @since axis1.1
555     */

556    public void setFaultNode(String JavaDoc node)
557    {
558       faultNode = node;
559    }
560
561    /**
562     * set the fault detail element to the arrary of details
563     *
564     * @param details list of detail elements, can be null
565     */

566    public void setFaultDetail(Element JavaDoc[] details)
567    {
568       if (details == null)
569       {
570          faultDetails = null;
571          return;
572       }
573
574       faultDetails = new Vector JavaDoc(details.length);
575       for (int loop = 0; loop < details.length; loop++)
576       {
577          faultDetails.add(details[loop]);
578       }
579    }
580
581    /**
582     * set the fault details to a string element.
583     *
584     * @param details XML fragment
585     */

586    public void setFaultDetailString(String JavaDoc details)
587    {
588       clearFaultDetails();
589       addFaultDetailString(details);
590    }
591
592    /**
593     * add a string tag to the fault details.
594     *
595     * @param detail XML fragment
596     */

597    public void addFaultDetailString(String JavaDoc detail)
598    {
599       initFaultDetails();
600       try
601       {
602          Document JavaDoc doc = XMLUtils.newDocument();
603          Element JavaDoc element = doc.createElement("string");
604          Text JavaDoc text = doc.createTextNode(detail);
605          element.appendChild(text);
606          faultDetails.add(element);
607       }
608       catch (ParserConfigurationException JavaDoc e)
609       {
610          // This should not occur
611
throw new InternalException(e);
612       }
613    }
614
615    /**
616     * append an element to the fault detail list
617     *
618     * @param detail the new element to add
619     * @since Axis1.1
620     */

621    public void addFaultDetail(Element JavaDoc detail)
622    {
623       initFaultDetails();
624       faultDetails.add(detail);
625    }
626
627    /**
628     * create an element of the given qname and add it to the details
629     *
630     * @param qname qname of the element
631     * @param body string to use as body
632     */

633    public void addFaultDetail(QName JavaDoc qname, String JavaDoc body)
634    {
635       Element JavaDoc detail = XMLUtils.StringToElement(qname.getNamespaceURI(),
636               qname.getLocalPart(),
637               body);
638
639       addFaultDetail(detail);
640    }
641
642    /**
643     * get all the fault details
644     *
645     * @return an array of fault details, or null for none
646     */

647    public Element JavaDoc[] getFaultDetails()
648    {
649       if (faultDetails == null)
650       {
651          return null;
652       }
653       Element JavaDoc result[] = new Element JavaDoc[faultDetails.size()];
654       for (int i = 0; i < result.length; i++)
655          result[i] = (Element JavaDoc)faultDetails.elementAt(i);
656       return result;
657    }
658
659    /**
660     * Find a fault detail element by its qname
661     *
662     * @param qname name of the node to look for
663     * @return the matching element or null
664     * @since axis1.1
665     */

666    public Element JavaDoc lookupFaultDetail(QName JavaDoc qname)
667    {
668       if (faultDetails != null)
669       {
670          //extract details from the qname. the empty namespace is represented
671
//by the empty string
672
String JavaDoc searchNamespace = qname.getNamespaceURI();
673          String JavaDoc searchLocalpart = qname.getLocalPart();
674          //now spin through the elements, seeking a match
675
Iterator JavaDoc it = faultDetails.iterator();
676          while (it.hasNext())
677          {
678             Element JavaDoc e = (Element JavaDoc)it.next();
679             String JavaDoc localpart = e.getLocalName();
680             if (localpart == null)
681             {
682                localpart = e.getNodeName();
683             }
684             String JavaDoc namespace = e.getNamespaceURI();
685             if (namespace == null)
686             {
687                namespace = "";
688             }
689             //we match on matching namespace and local part; empty namespace
690
//in an element may be null, which matches QName's ""
691
if (searchNamespace.equals(namespace)
692                     && searchLocalpart.equals(localpart))
693             {
694                return e;
695             }
696          }
697       }
698       return null;
699    }
700
701    /**
702     * find and remove a specified fault detail element
703     *
704     * @param qname qualified name of detail
705     * @return true if it was found and removed
706     * @since axis1.1
707     */

708    public boolean removeFaultDetail(QName JavaDoc qname)
709    {
710       Element JavaDoc elt = lookupFaultDetail(qname);
711       if (elt == null)
712       {
713          return false;
714       }
715       else
716       {
717          return faultDetails.remove(elt);
718       }
719    }
720
721    /**
722     * add this fault and any needed headers to the output context
723     *
724     * @param context
725     * @throws Exception
726     */

727    public void output(SerializationContext context) throws Exception JavaDoc
728    {
729
730       SOAPConstants soapConstants = Constants.DEFAULT_SOAP_VERSION;
731       if (context.getMessageContext() != null)
732          soapConstants = context.getMessageContext().getSOAPConstants();
733
734       SOAPEnvelopeAxisImpl envelope = new SOAPEnvelopeAxisImpl(soapConstants);
735
736       SOAPFaultImpl fault = new SOAPFaultImpl(this);
737       envelope.addBodyElement(fault);
738
739       // add any headers we need
740
if (faultHeaders != null)
741       {
742          for (Iterator JavaDoc i = faultHeaders.iterator(); i.hasNext();)
743          {
744             SOAPHeaderElementAxisImpl header = (SOAPHeaderElementAxisImpl)i.next();
745             envelope.addHeader(header);
746          }
747       }
748
749       envelope.output(context);
750    }
751
752    /**
753     * string operator
754     *
755     * @return the current fault string; may be empty but never null
756     */

757    public String JavaDoc toString()
758    {
759       return getClass().getName() + ": " + faultString;
760    }
761
762    /**
763     * The override of the base class method prints out the
764     * fault info before the stack trace
765     *
766     * @param ps where to print
767     */

768    public void printStackTrace(PrintStream JavaDoc ps)
769    {
770       ps.println(dumpToString());
771       super.printStackTrace(ps);
772    }
773
774    /**
775     * The override of the base class method prints out the
776     * fault info before the stack trace
777     *
778     * @param pw where to print
779     */

780    public void printStackTrace(java.io.PrintWriter JavaDoc pw)
781    {
782       pw.println(dumpToString());
783       super.printStackTrace(pw);
784    }
785
786    /**
787     * Add a SOAP header which should be serialized along with the fault.
788     *
789     * @param header a SOAPHeaderElement containing some fault-relevant stuff
790     */

791    public void addHeader(SOAPHeaderElementAxisImpl header)
792    {
793       if (faultHeaders == null)
794       {
795          faultHeaders = new ArrayList JavaDoc();
796       }
797       faultHeaders.add(header);
798    }
799
800    /**
801     * Get the SOAP headers associated with this fault.
802     *
803     * @return an ArrayList containing any headers associated with this fault
804     */

805    public ArrayList JavaDoc getHeaders()
806    {
807       return faultHeaders;
808    }
809
810    /**
811     * clear all fault headers
812     */

813    public void clearHeaders()
814    {
815       faultHeaders = null;
816    }
817
818
819    /**
820     * Writes any exception data to the faultDetails
821     * This can be overrided (and is) by emitted exception clases.
822     * The base implementation will attempt to serialize exception data
823     * the fault was created from an Exception and a type mapping is found for it.
824     */

825    public void writeDetails(QName JavaDoc qname, SerializationContext context) throws java.io.IOException JavaDoc
826    {
827
828       Object JavaDoc detailObject = this.detail;
829       if (detailObject == null)
830          return;
831
832       Serializer ser = context.getSerializerForJavaType(detailObject.getClass());
833       if (ser != null)
834       {
835          boolean oldMR = context.getDoMultiRefs();
836          context.setDoMultiRefs(false);
837          context.serialize(qname, null, detailObject);
838          context.setDoMultiRefs(oldMR);
839       }
840    }
841 }
842
Popular Tags