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