1 package org.codehaus.xfire.fault;
2
3 import java.io.PrintStream;
4 import java.io.PrintWriter;
5 import java.util.HashMap;
6 import java.util.Map;
7
8 import org.codehaus.xfire.XFireException;
9 import org.codehaus.yom.Element;
10
11 /***
12 * In XFire, applications throw their own declared exceptions which are then turned into faults. The
13 * <code>XFireFault</code> class wraps these exceptions extracting out the details for the fault message.
14 * <p/>
15 * If the developer wishes to generate their own custom fault messages, they can either override XFireFault to provide
16 * the FaultHandlers with the necessary information or write a new FaultHandler. </p>
17 * <p/>
18 * TODO Add i18n support
19 *
20 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
21 * @since Feb 14, 2004
22 */
23 public class XFireFault
24 extends XFireException
25 {
26 /***
27 * Serialization ID.
28 */
29 private static final long serialVersionUID = 1L;
30
31 /***
32 * Fault codes.
33 */
34 public final static String VERSION_MISMATCH = "VersionMismatch";
35 public final static String MUST_UNDERSTAND = "MustUnderstand";
36 public final static String DATA_ENCODING_UNKNOWN = "DataEncodingUnknown";
37
38 /***
39 * "The message was incorrectly formed or did not contain the appropriate information in order to succeed." -- SOAP
40 * 1.2 Spec
41 */
42 public final static String SENDER = "Sender";
43
44 /***
45 * A SOAP 1.2 only fault code.
46 * <p/>
47 * "The message could not be processed for reasons attributable to the processing of the message rather than to the
48 * contents of the message itself." -- SOAP 1.2 Spec
49 * <p/>
50 * If this message is used in a SOAP 1.1 Fault it will most likely (depending on the FaultHandler) be mapped to
51 * "Sender" instead.
52 */
53 public final static String RECEIVER = "Receiver";
54
55 private String faultCode;
56 private String subCode;
57 private String message;
58 private String role;
59 private Element detail;
60 private Map namespaces;
61 private Throwable cause;
62
63 /***
64 * Creates a <code>XFireFault</code> from the given throwable. If the throwable is a <code>XFireFault</code>, it is
65 * not wrapped.
66 *
67 * @param throwable the throwable
68 * @return the fault
69 */
70 public static XFireFault createFault(Throwable throwable)
71 {
72 XFireFault fault = null;
73
74 if (throwable instanceof XFireFault)
75 {
76 fault = (XFireFault) throwable;
77 }
78 else
79 {
80 fault = new XFireFault(throwable);
81 }
82
83 return fault;
84 }
85
86 protected XFireFault()
87 {
88 }
89
90 /***
91 * Create a fault for the specified exception. The faultCode is set to RECEIVER.
92 *
93 * @param throwable
94 */
95 public XFireFault(Throwable throwable)
96 {
97 this(throwable.getMessage(), throwable, RECEIVER);
98 }
99
100 /***
101 * Create a fault with the specified faultCode. The exception message is used for the fault message.
102 *
103 * @param throwable The exception that caused this fault.
104 * @param code The fault code. See XFireFault's static fields.
105 */
106 public XFireFault(Throwable throwable, String code)
107 {
108 this(throwable.getMessage(), throwable, code);
109 }
110
111 /***
112 * Create an exception wih the specified fault message and faultCode.
113 *
114 * @param message The fault message.
115 * @param code The fault code. See XFireFault's static fields.
116 */
117 public XFireFault(String message, String code)
118 {
119 this(message, null, code);
120 }
121
122 /***
123 * Create a fault.
124 *
125 * @param cause The exception which caused this fault.
126 * @param code The fault code. See XFireFault's static fields.
127 */
128 public XFireFault(String message,
129 Throwable cause,
130 String code)
131 {
132 this.message = message != null ? message : "Fault";
133 this.faultCode = code;
134 this.cause = cause;
135 this.namespaces = new HashMap();
136 }
137
138 /***
139 * Adds a namespace with prefix to this fault.
140 *
141 * @param prefix the prefix
142 * @param ns the namespace.
143 */
144 public void addNamespace(String prefix, String ns)
145 {
146 namespaces.put(prefix, ns);
147 }
148
149 /***
150 * Prints this throwable and its backtrace to the specified print stream.
151 *
152 * @param s <code>PrintStream</code> to use for output
153 */
154 public void printStackTrace(PrintStream s)
155 {
156 if (this.cause == null || this.cause == this)
157 {
158 super.printStackTrace(s);
159 }
160 else
161 {
162 s.println(this);
163 this.cause.printStackTrace(s);
164 }
165 }
166
167 /***
168 * Prints this throwable and its backtrace to the specified print writer.
169 *
170 * @param w <code>PrintWriter</code> to use for output
171 */
172 public void printStackTrace(PrintWriter w)
173 {
174 if (this.cause == null || this.cause == this)
175 {
176 super.printStackTrace(w);
177 }
178 else
179 {
180 w.println(this);
181 this.cause.printStackTrace(w);
182 }
183 }
184
185 /***
186 * Returns the cause of this throwable or <code>null</code> if the cause is nonexistent or unknown.
187 *
188 * @return the nested cause.
189 */
190 public Throwable getCause()
191 {
192 return (this.cause == this ? null : this.cause);
193 }
194
195 /***
196 * Returns the detail node. If no detail node has been set, an empty <code><detail></code> is created.
197 *
198 * @return the detail node.
199 */
200 public Element getDetail()
201 {
202 if (detail == null)
203 {
204 detail = new Element("detail");
205 }
206 return detail;
207 }
208
209 /***
210 * Sets a details <code>Node</code> on this fault.
211 *
212 * @param details the detail node.
213 */
214 public void setDetail(Element details)
215 {
216 detail = details;
217 }
218
219 /***
220 * Returns the fault code of this fault.
221 *
222 * @return the fault code.
223 */
224 public String getFaultCode()
225 {
226 return faultCode;
227 }
228
229 /***
230 * Sets the fault code of this fault.
231 *
232 * @param faultCode the fault code.
233 */
234 public void setFaultCode(String faultCode)
235 {
236 this.faultCode = faultCode;
237 }
238
239 /***
240 * Returns the detail message string of this fault.
241 *
242 * @return the detail message string of this <code>XfireFault</code> (which may be <code>null</code>)
243 */
244 public String getMessage()
245 {
246 return message;
247 }
248
249 /***
250 * @param message The message to set.
251 */
252 public void setMessage(String message)
253 {
254 this.message = message;
255 }
256
257 /***
258 * User defined namespaces which will be written out on the resultant SOAP Fault (for use easy with SubCodes and
259 * Detail) elements.
260 *
261 * @return
262 */
263 public Map getNamespaces()
264 {
265 return namespaces;
266 }
267
268 public String getReason()
269 {
270 return getMessage();
271 }
272
273 /***
274 * Returns the fault actor.
275 *
276 * @return the fault actor.
277 */
278 public String getRole()
279 {
280 return role;
281 }
282
283 /***
284 * Sets the fault actor.
285 *
286 * @param actor the actor.
287 */
288 public void setRole(String actor)
289 {
290 this.role = actor;
291 }
292
293 /***
294 * Returns the SubCode for the Fault Code.
295 *
296 * @return The SubCode element as detailed by the SOAP 1.2 spec.
297 */
298 public String getSubCode()
299 {
300 return subCode;
301 }
302
303 /***
304 * Sets the SubCode for the Fault Code.
305 *
306 * @param subCode The SubCode element as detailed by the SOAP 1.2 spec.
307 */
308 public void setSubCode(String subCode)
309 {
310 this.subCode = subCode;
311 }
312
313 /***
314 * Indicates whether this fault has a detail message.
315 *
316 * @return <code>true</code> if this fault has a detail message; <code>false</code> otherwise.
317 */
318 public boolean hasDetails()
319 {
320 return detail == null ? false : true;
321 }
322 }
323