Christian van Spaandonk | 569a4c5 | 2008-08-02 09:56:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * $Header: /cvshome/build/info.dmtree/src/info/dmtree/DmtException.java,v 1.9 2006/07/12 21:21:37 hargrave Exp $ |
| 3 | * |
| 4 | * Copyright (c) OSGi Alliance (2004, 2006). All Rights Reserved. |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | package info.dmtree; |
| 19 | |
| 20 | import java.io.PrintStream; |
| 21 | import java.util.Vector; |
| 22 | |
| 23 | /** |
| 24 | * Checked exception received when a DMT operation fails. Beside the exception |
| 25 | * message, a <code>DmtException</code> always contains an error code (one of |
| 26 | * the constants specified in this class), and may optionally contain the URI of |
| 27 | * the related node, and information about the cause of the exception. |
| 28 | * <p> |
| 29 | * Some of the error codes defined in this class have a corresponding error code |
| 30 | * defined in OMA DM, in these cases the name and numerical value from OMA DM is |
| 31 | * used. Error codes without counterparts in OMA DM were given numbers from a |
| 32 | * different range, starting from 1. |
| 33 | * <p> |
| 34 | * The cause of the exception (if specified) can either be a single |
| 35 | * <code>Throwable</code> instance, or a list of such instances if several |
| 36 | * problems occurred during the execution of a method. An example for the latter |
| 37 | * is the <code>close</code> method of <code>DmtSession</code> that tries to |
| 38 | * close multiple plugins, and has to report the exceptions of all failures. |
| 39 | * <p> |
| 40 | * Each constructor has two variants, one accepts a <code>String</code> node |
| 41 | * URI, the other accepts a <code>String[]</code> node path. The former is |
| 42 | * used by the DmtAdmin implementation, the latter by the plugins, who receive |
| 43 | * the node URI as an array of segment names. The constructors are otherwise |
| 44 | * identical. |
| 45 | * <p> |
| 46 | * Getter methods are provided to retrieve the values of the additional |
| 47 | * parameters, and the <code>printStackTrace(PrintWriter)</code> method is |
| 48 | * extended to print the stack trace of all causing throwables as well. |
| 49 | */ |
| 50 | public class DmtException extends Exception { |
| 51 | private static final long serialVersionUID = -63006267148118655L; |
| 52 | |
| 53 | // ----- Public constants -----// |
| 54 | |
| 55 | /** |
| 56 | * The originator's authentication credentials specify a principal with |
| 57 | * insufficient rights to complete the command. |
| 58 | * <p> |
| 59 | * This status code is used as response to device originated sessions if the |
| 60 | * remote management server cannot authorize the device to perform the |
| 61 | * requested operation. |
| 62 | * <p> |
| 63 | * This error code corresponds to the OMA DM response status code 401 |
| 64 | * "Unauthorized". |
| 65 | */ |
| 66 | public static final int UNAUTHORIZED = 401; |
| 67 | |
| 68 | /** |
| 69 | * The requested target node was not found. No indication is given as to |
| 70 | * whether this is a temporary or permanent condition, unless otherwise |
| 71 | * noted. |
| 72 | * <p> |
| 73 | * This is only used when the requested node name is valid, otherwise the |
| 74 | * more specific error codes {@link #URI_TOO_LONG} or {@link #INVALID_URI} |
| 75 | * are used. This error code corresponds to the OMA DM response status code |
| 76 | * 404 "Not Found". |
| 77 | */ |
| 78 | public static final int NODE_NOT_FOUND = 404; |
| 79 | |
| 80 | /** |
| 81 | * The requested command is not allowed on the target node. This includes |
| 82 | * the following situations: |
| 83 | * <ul> |
| 84 | * <li>an interior node operation is requested for a leaf node, or vice |
| 85 | * versa (e.g. trying to retrieve the children of a leaf node) |
| 86 | * <li>an attempt is made to create a node where the parent is a leaf node |
| 87 | * <li>an attempt is made to rename or delete the root node of the tree |
| 88 | * <li>an attempt is made to rename or delete the root node of the session |
| 89 | * <li>a write operation (other than setting the ACL) is performed in a |
| 90 | * non-atomic write session on a node provided by a plugin that is read-only |
| 91 | * or does not support non-atomic writing |
| 92 | * <li>a node is copied to its descendant |
| 93 | * <li>the ACL of the root node is changed not to include Add rights for |
| 94 | * all principals |
| 95 | * </ul> |
| 96 | * <p> |
| 97 | * This error code corresponds to the OMA DM response status code 405 |
| 98 | * "Command not allowed". |
| 99 | */ |
| 100 | public static final int COMMAND_NOT_ALLOWED = 405; |
| 101 | |
| 102 | /** |
| 103 | * The requested command failed because an optional feature required by the |
| 104 | * command is not supported. For example, opening an atomic session might |
| 105 | * return this error code if the DmtAdmin implementation does not support |
| 106 | * transactions. Similarly, accessing the optional node properties (Title, |
| 107 | * Timestamp, Version, Size) might not succeed if either the DmtAdmin |
| 108 | * implementation or the underlying plugin does not support the property. |
| 109 | * <p> |
| 110 | * When getting or setting values for interior nodes (an optional |
| 111 | * optimization feature), a plugin can use this error code to indicate that |
| 112 | * the given interior node does not support values. |
| 113 | * <p> |
| 114 | * This error code corresponds to the OMA DM response status code 406 |
| 115 | * "Optional feature not supported". |
| 116 | */ |
| 117 | public static final int FEATURE_NOT_SUPPORTED = 406; |
| 118 | |
| 119 | /** |
| 120 | * The requested command failed because the target URI or one of its |
| 121 | * segments is too long for what the recipient is able or willing to |
| 122 | * process, or the target URI contains too many segments. The length and |
| 123 | * segment number limits are implementation dependent, their minimum values |
| 124 | * can be found in the Non Functional Requirements section of the OSGi |
| 125 | * specification. |
| 126 | * <p> |
| 127 | * The {@link Uri#mangle(String)} method provides support for ensuring that |
| 128 | * a URI segment conforms to the length limits set by the implementation. |
| 129 | * <p> |
| 130 | * This error code corresponds to the OMA DM response status code 414 |
| 131 | * "URI too long". |
| 132 | * |
| 133 | * @see "OSGi Service Platform, Mobile Specification Release 4" |
| 134 | */ |
| 135 | public static final int URI_TOO_LONG = 414; |
| 136 | |
| 137 | /** |
| 138 | * The requested node creation operation failed because the target already |
| 139 | * exists. This can occur if the node is created directly (with one of the |
| 140 | * <code>create...</code> methods), or indirectly (during a |
| 141 | * <code>copy</code> operation). |
| 142 | * <p> |
| 143 | * This error code corresponds to the OMA DM response status code 418 |
| 144 | * "Already exists". |
| 145 | */ |
| 146 | public static final int NODE_ALREADY_EXISTS = 418; |
| 147 | |
| 148 | /** |
| 149 | * The requested command failed because the principal associated with the |
| 150 | * session does not have adequate access control permissions (ACL) on the |
| 151 | * target. This can only appear in case of remote sessions, i.e. if the |
| 152 | * session is associated with an authenticated principal. |
| 153 | * <p> |
| 154 | * This error code corresponds to the OMA DM response status code 425 |
| 155 | * "Permission denied". |
| 156 | */ |
| 157 | public static final int PERMISSION_DENIED = 425; |
| 158 | |
| 159 | /** |
| 160 | * The recipient encountered an error which prevented it from fulfilling the |
| 161 | * request. |
| 162 | * <p> |
| 163 | * This error code is only used in situations not covered by any of the |
| 164 | * other error codes that a method may use. Some methods specify more |
| 165 | * specific error situations for this code, but it can generally be used for |
| 166 | * any unexpected condition that causes the command to fail. |
| 167 | * <p> |
| 168 | * This error code corresponds to the OMA DM response status code 500 |
| 169 | * "Command Failed". |
| 170 | */ |
| 171 | public static final int COMMAND_FAILED = 500; |
| 172 | |
| 173 | /** |
| 174 | * An error related to the recipient data store occurred while processing |
| 175 | * the request. This error code may be thrown by any of the methods |
| 176 | * accessing the tree, but whether it is really used depends on the |
| 177 | * implementation, and the data store it uses. |
| 178 | * <p> |
| 179 | * This error code corresponds to the OMA DM response status code 510 |
| 180 | * "Data store failure". |
| 181 | */ |
| 182 | public static final int DATA_STORE_FAILURE = 510; |
| 183 | |
| 184 | /** |
| 185 | * The rollback command was not completed successfully. The tree might be in |
| 186 | * an inconsistent state after this error. |
| 187 | * <p> |
| 188 | * This error code corresponds to the OMA DM response status code 516 |
| 189 | * "Atomic roll back failed". |
| 190 | */ |
| 191 | public static final int ROLLBACK_FAILED = 516; |
| 192 | |
| 193 | |
| 194 | /** |
| 195 | * A device initiated remote operation failed. This is used when the |
| 196 | * protocol adapter fails to send an alert for any reason. |
| 197 | * <p> |
| 198 | * Alert routing errors (that occur while looking for the proper protocol |
| 199 | * adapter to use) are indicated by {@link #ALERT_NOT_ROUTED}, this code is |
| 200 | * only for errors encountered while sending the routed alert. This error |
| 201 | * code does not correspond to any OMA DM response status code. It should be |
| 202 | * translated to the code 500 "Command Failed" when transferring |
| 203 | * over OMA DM. |
| 204 | */ |
| 205 | public static final int REMOTE_ERROR = 1; |
| 206 | |
| 207 | /** |
| 208 | * Operation failed because of meta data restrictions. This covers any |
| 209 | * attempted deviation from the parameters defined by the |
| 210 | * <code>MetaNode</code> objects of the affected nodes, for example in the |
| 211 | * following situations: |
| 212 | * <ul> |
| 213 | * <li>creating, deleting or renaming a permanent node, or modifying its |
| 214 | * type or value |
| 215 | * <li>creating an interior node where the meta-node defines it as a leaf, |
| 216 | * or vice versa |
| 217 | * <li>any operation on a node which does not have the required access type |
| 218 | * (e.g. executing a node that lacks the <code>MetaNode.CMD_EXECUTE</code> |
| 219 | * access type) |
| 220 | * <li>any node creation or deletion that would violate the cardinality |
| 221 | * constraints |
| 222 | * <li>any leaf node value setting that would violate the allowed formats, |
| 223 | * values, mime types, etc. |
| 224 | * <li>any node creation that would violate the allowed node names |
| 225 | * </ul> |
| 226 | * <p> |
| 227 | * This error code can also be used to indicate any other meta data |
| 228 | * violation, even if it cannot be described by the <code>MetaNode</code> |
| 229 | * class. For example, detecting a multi-node constraint violation while |
| 230 | * committing an atomic session should result in this error. |
| 231 | * <p> |
| 232 | * This error code does not correspond to any OMA DM response status code. |
| 233 | * It should be translated to the code 405 "Command not allowed" |
| 234 | * when transferring over OMA DM. |
| 235 | */ |
| 236 | public static final int METADATA_MISMATCH = 2; |
| 237 | |
| 238 | /** |
| 239 | * The requested command failed because the target URI or node name is |
| 240 | * <code>null</code> or syntactically invalid. This covers the following |
| 241 | * cases: |
| 242 | * <ul> |
| 243 | * <li>the URI or node name ends with the '\' or '/' character |
| 244 | * <li>the URI is an empty string (only invalid if the method does not |
| 245 | * accept relative URIs) |
| 246 | * <li>the URI contains the segment "<code>.</code>" at a position |
| 247 | * other than the beginning of the URI |
| 248 | * <li>the node name is "<code>..</code>" or the URI contains such |
| 249 | * a segment |
| 250 | * <li>the node name is an empty string or the URI contains an empty segment |
| 251 | * <li>the node name contains an unescaped '/' character |
| 252 | * </ul> |
| 253 | * <p> |
| 254 | * See the {@link Uri#mangle(String)} method for support on escaping invalid |
| 255 | * characters in a URI. |
| 256 | * <p> |
| 257 | * This code is only used if the URI or node name does not match any of the |
| 258 | * criteria for {@link #URI_TOO_LONG}. This error code does not correspond |
| 259 | * to any OMA DM response status code. It should be translated to the code |
| 260 | * 404 "Not Found" when transferring over OMA DM. |
| 261 | */ |
| 262 | public static final int INVALID_URI = 3; |
| 263 | |
| 264 | /** |
| 265 | * An error occurred related to concurrent access of nodes. This can happen |
| 266 | * for example if a configuration node was deleted directly through the |
| 267 | * Configuration Admin service, while the node was manipulated via the tree. |
| 268 | * <p> |
| 269 | * This error code does not correspond to any OMA DM response status code. |
| 270 | * It should be translated to the code 500 "Command Failed" when |
| 271 | * transferring over OMA DM. |
| 272 | */ |
| 273 | public static final int CONCURRENT_ACCESS = 4; |
| 274 | |
| 275 | /** |
| 276 | * An alert can not be sent from the device to the given principal. This can |
| 277 | * happen if there is no Remote Alert Sender willing to forward the alert to |
| 278 | * the given principal, or if no principal was given and the DmtAdmin did |
| 279 | * not find an appropriate default destination. |
| 280 | * <p> |
| 281 | * This error code does not correspond to any OMA DM response status code. |
| 282 | * It should be translated to the code 500 "Command Failed" when |
| 283 | * transferring over OMA DM. |
| 284 | */ |
| 285 | public static final int ALERT_NOT_ROUTED = 5; |
| 286 | |
| 287 | /** |
| 288 | * A transaction-related error occurred in an atomic session. This error is |
| 289 | * caused by one of the following situations: |
| 290 | * <ul> |
| 291 | * <li>an updating method within an atomic session can not be executed |
| 292 | * because the underlying plugin is read-only or does not support atomic |
| 293 | * writing</li> |
| 294 | * <li>a commit operation at the end of an atomic session failed because |
| 295 | * one of the underlying plugins failed to close</li> |
| 296 | * </ul> |
| 297 | * The latter case may leave the tree in an inconsistent state due to the |
| 298 | * lack of a two-phase commit system, see {@link DmtSession#commit} for |
| 299 | * details. |
| 300 | * <p> |
| 301 | * This error code does not correspond to any OMA DM response status code. |
| 302 | * It should be translated to the code 500 "Command Failed" when |
| 303 | * transferring over OMA DM. |
| 304 | */ |
| 305 | public static final int TRANSACTION_ERROR = 6; |
| 306 | |
| 307 | /** |
| 308 | * Creation of a session timed out because of another ongoing session. The |
| 309 | * length of time while the DmtAdmin waits for the blocking session(s) to |
| 310 | * finish is implementation dependant. |
| 311 | * <p> |
| 312 | * This error code does not correspond to any OMA DM response status code. |
| 313 | * OMA has several status codes related to timeout, but these are meant to |
| 314 | * be used when a request times out, not if a session can not be |
| 315 | * established. This error code should be translated to the code 500 |
| 316 | * "Command Failed" when transferring over OMA DM. |
| 317 | */ |
| 318 | public static final int SESSION_CREATION_TIMEOUT = 7; |
| 319 | |
| 320 | // ----- Content fields -----// |
| 321 | |
| 322 | /** |
| 323 | * The URI of the node on which the failed DMT operation was issued, or |
| 324 | * <code>null</code> if the operation was not associated with a node. |
| 325 | */ |
| 326 | private final String uri; |
| 327 | |
| 328 | /** |
| 329 | * The error code of the failure, one of the constants defined in this |
| 330 | * class. |
| 331 | */ |
| 332 | private final int code; |
| 333 | |
| 334 | /** |
| 335 | * The message associated with the exception, or <code>null</code> if |
| 336 | * there is no error message. |
| 337 | */ |
| 338 | private final String message; |
| 339 | |
| 340 | /** |
| 341 | * The list of originating exceptions, or empty list or <code>null</code> |
| 342 | * if there are no originating exceptions. |
| 343 | */ |
| 344 | private final Throwable[] causes; |
| 345 | |
| 346 | /** |
| 347 | * Determines whether the exception is fatal or not. This is basically a |
| 348 | * two-state severity indicator, with the 'fatal' severity being the more |
| 349 | * serious one. |
| 350 | */ |
| 351 | private final boolean fatal; |
| 352 | |
| 353 | // ----- Constructors -----// |
| 354 | |
| 355 | /** |
| 356 | * Create an instance of the exception. The <code>uri</code> and |
| 357 | * <code>message</code> parameters are optional. No originating exception |
| 358 | * is specified. |
| 359 | * |
| 360 | * @param uri the node on which the failed DMT operation was issued, or |
| 361 | * <code>null</code> if the operation is not associated with a node |
| 362 | * @param code the error code of the failure |
| 363 | * @param message the message associated with the exception, or |
| 364 | * <code>null</code> if there is no error message |
| 365 | */ |
| 366 | public DmtException(String uri, int code, String message) { |
| 367 | this(uri, code, message, new Throwable[0], false); |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Create an instance of the exception, specifying the cause exception. The |
| 372 | * <code>uri</code>, <code>message</code> and <code>cause</code> |
| 373 | * parameters are optional. |
| 374 | * |
| 375 | * @param uri the node on which the failed DMT operation was issued, or |
| 376 | * <code>null</code> if the operation is not associated with a node |
| 377 | * @param code the error code of the failure |
| 378 | * @param message the message associated with the exception, or |
| 379 | * <code>null</code> if there is no error message |
| 380 | * @param cause the originating exception, or <code>null</code> if there |
| 381 | * is no originating exception |
| 382 | */ |
| 383 | public DmtException(String uri, int code, String message, Throwable cause) { |
| 384 | this(uri, code, message, (cause == null) ? new Throwable[0] |
| 385 | : new Throwable[] { cause }, false); |
| 386 | } |
| 387 | |
| 388 | /** |
| 389 | * Create an instance of the exception, specifying the list of cause |
| 390 | * exceptions and whether the exception is a fatal one. This constructor is |
| 391 | * meant to be used by plugins wishing to indicate that a serious error |
| 392 | * occurred which should invalidate the ongoing atomic session. The |
| 393 | * <code>uri</code>, <code>message</code> and <code>causes</code> |
| 394 | * parameters are optional. |
| 395 | * <p> |
| 396 | * If a fatal exception is thrown, no further business methods will be |
| 397 | * called on the originator plugin. In case of atomic sessions, all other |
| 398 | * open plugins will be rolled back automatically, except if the fatal |
| 399 | * exception was thrown during commit. |
| 400 | * |
| 401 | * @param uri the node on which the failed DMT operation was issued, or |
| 402 | * <code>null</code> if the operation is not associated with a node |
| 403 | * @param code the error code of the failure |
| 404 | * @param message the message associated with the exception, or |
| 405 | * <code>null</code> if there is no error message |
| 406 | * @param causes the list of originating exceptions, or empty list or |
| 407 | * <code>null</code> if there are no originating exceptions |
| 408 | * @param fatal whether the exception is fatal |
| 409 | */ |
| 410 | public DmtException(String uri, int code, String message, Vector causes, |
| 411 | boolean fatal) { |
| 412 | this(uri, code, message, (causes == null) ? new Throwable[0] |
| 413 | : (Throwable[]) causes.toArray(new Throwable[causes.size()]), |
| 414 | fatal); |
| 415 | } |
| 416 | |
| 417 | private DmtException(String uri, int code, String message, |
| 418 | Throwable[] causes, boolean fatal) { |
| 419 | this.uri = uri; |
| 420 | this.code = code; |
| 421 | this.message = message; |
| 422 | this.causes = causes; |
| 423 | this.fatal = fatal; |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * Create an instance of the exception, specifying the target node as an |
| 428 | * array of path segments. This method behaves in exactly the same way as if |
| 429 | * the path was given as a URI string. |
| 430 | * |
| 431 | * @param path the path of the node on which the failed DMT operation was |
| 432 | * issued, or <code>null</code> if the operation is not associated |
| 433 | * with a node |
| 434 | * @param code the error code of the failure |
| 435 | * @param message the message associated with the exception, or |
| 436 | * <code>null</code> if there is no error message |
| 437 | * @see #DmtException(String, int, String) |
| 438 | */ |
| 439 | public DmtException(String[] path, int code, String message) { |
| 440 | this(pathToUri(path), code, message); |
| 441 | } |
| 442 | |
| 443 | /** |
| 444 | * Create an instance of the exception, specifying the target node as an |
| 445 | * array of path segments, and specifying the cause exception. This method |
| 446 | * behaves in exactly the same way as if the path was given as a URI string. |
| 447 | * |
| 448 | * @param path the path of the node on which the failed DMT operation was |
| 449 | * issued, or <code>null</code> if the operation is not associated |
| 450 | * with a node |
| 451 | * @param code the error code of the failure |
| 452 | * @param message the message associated with the exception, or |
| 453 | * <code>null</code> if there is no error message |
| 454 | * @param cause the originating exception, or <code>null</code> if there |
| 455 | * is no originating exception |
| 456 | * @see #DmtException(String, int, String, Throwable) |
| 457 | */ |
| 458 | public DmtException(String[] path, int code, String message, Throwable cause) { |
| 459 | this(pathToUri(path), code, message, cause); |
| 460 | } |
| 461 | |
| 462 | /** |
| 463 | * Create an instance of the exception, specifying the target node as an |
| 464 | * array of path segments, the list of cause exceptions, and whether the |
| 465 | * exception is a fatal one. This method behaves in exactly the same way as |
| 466 | * if the path was given as a URI string. |
| 467 | * |
| 468 | * @param path the path of the node on which the failed DMT operation was |
| 469 | * issued, or <code>null</code> if the operation is not associated |
| 470 | * with a node |
| 471 | * @param code the error code of the failure |
| 472 | * @param message the message associated with the exception, or |
| 473 | * <code>null</code> if there is no error message |
| 474 | * @param causes the list of originating exceptions, or empty list or |
| 475 | * <code>null</code> if there are no originating exceptions |
| 476 | * @param fatal whether the exception is fatal |
| 477 | * @see #DmtException(String, int, String, Vector, boolean) |
| 478 | */ |
| 479 | public DmtException(String[] path, int code, String message, Vector causes, |
| 480 | boolean fatal) { |
| 481 | this(pathToUri(path), code, message, causes, fatal); |
| 482 | } |
| 483 | |
| 484 | // ----- Public methods -----// |
| 485 | |
| 486 | /** |
| 487 | * Get the node on which the failed DMT operation was issued. Some |
| 488 | * operations like <code>DmtSession.close()</code> don't require an URI, |
| 489 | * in this case this method returns <code>null</code>. |
| 490 | * |
| 491 | * @return the URI of the node, or <code>null</code> |
| 492 | */ |
| 493 | public String getURI() { |
| 494 | return uri; |
| 495 | } |
| 496 | |
| 497 | /** |
| 498 | * Get the error code associated with this exception. Most of the error |
| 499 | * codes within this exception correspond to OMA DM error codes. |
| 500 | * |
| 501 | * @return the error code |
| 502 | */ |
| 503 | public int getCode() { |
| 504 | return code; |
| 505 | } |
| 506 | |
| 507 | /** |
| 508 | * Get the message associated with this exception. The returned string also |
| 509 | * contains the associated URI (if any) and the exception code. The |
| 510 | * resulting message has the following format (parts in square brackets are |
| 511 | * only included if the field inside them is not <code>null</code>): |
| 512 | * |
| 513 | * <pre> |
| 514 | * <exception_code>[: '<uri>'][: <error_message>] |
| 515 | * </pre> |
| 516 | * |
| 517 | * @return the error message in the format described above |
| 518 | */ |
| 519 | public String getMessage() { |
| 520 | StringBuffer sb = new StringBuffer(getCodeText(code)); |
| 521 | if (uri != null) |
| 522 | sb.append(": '").append(uri).append('\''); |
| 523 | if (message != null) |
| 524 | sb.append(": ").append(message); |
| 525 | |
| 526 | return sb.toString(); |
| 527 | } |
| 528 | |
| 529 | /** |
| 530 | * Get the cause of this exception. Returns non-<code>null</code>, if |
| 531 | * this exception is caused by one or more other exceptions (like a |
| 532 | * <code>NullPointerException</code> in a DmtPlugin). If there are more |
| 533 | * than one cause exceptions, the first one is returned. |
| 534 | * |
| 535 | * @return the cause of this exception, or <code>null</code> if no cause |
| 536 | * was given |
| 537 | */ |
| 538 | public Throwable getCause() { |
| 539 | return causes.length == 0 ? null : causes[0]; |
| 540 | } |
| 541 | |
| 542 | /** |
| 543 | * Get all causes of this exception. Returns the causing exceptions in an |
| 544 | * array. If no cause was specified, an empty array is returned. |
| 545 | * |
| 546 | * @return the list of causes of this exception |
| 547 | */ |
| 548 | public Throwable[] getCauses() { |
| 549 | return (Throwable[]) causes.clone(); |
| 550 | } |
| 551 | |
| 552 | /** |
| 553 | * Check whether this exception is marked as fatal in the session. Fatal |
| 554 | * exceptions trigger an automatic rollback of atomic sessions. |
| 555 | * |
| 556 | * @return whether the exception is marked as fatal |
| 557 | */ |
| 558 | public boolean isFatal() { |
| 559 | return fatal; |
| 560 | } |
| 561 | |
| 562 | /** |
| 563 | * Prints the exception and its backtrace to the specified print stream. Any |
| 564 | * causes that were specified for this exception are also printed, together |
| 565 | * with their backtraces. |
| 566 | * |
| 567 | * @param s <code>PrintStream</code> to use for output |
| 568 | */ |
| 569 | public void printStackTrace(PrintStream s) { |
| 570 | super.printStackTrace(s); |
| 571 | for (int i = 0; i<causes.length; i++) { |
| 572 | s.print("Caused by" + (i > 0 ? " (" + (i+1) + ")" : "") + ": "); |
| 573 | causes[i].printStackTrace(s); |
| 574 | } |
| 575 | } |
| 576 | |
| 577 | // ----- Utility methods -----// |
| 578 | |
| 579 | /** |
| 580 | * Converts the given path, given as an array of path segments, to a single |
| 581 | * URI string. |
| 582 | * |
| 583 | * @param path the path to convert |
| 584 | * @return the URI string representing the same node as the given path |
| 585 | */ |
| 586 | static String pathToUri(String[] path) { |
| 587 | if (path == null) |
| 588 | return null; |
| 589 | |
| 590 | return Uri.toUri(path); |
| 591 | } |
| 592 | |
| 593 | /** |
| 594 | * Returns the name of the given error code. |
| 595 | * |
| 596 | * @param code the error code |
| 597 | * @return a string containing the error code name |
| 598 | */ |
| 599 | private static String getCodeText(int code) { |
| 600 | // todo sync codes |
| 601 | switch (code) { |
| 602 | case NODE_NOT_FOUND: |
| 603 | return "NODE_NOT_FOUND"; |
| 604 | case COMMAND_NOT_ALLOWED: |
| 605 | return "COMMAND_NOT_ALLOWED"; |
| 606 | case FEATURE_NOT_SUPPORTED: |
| 607 | return "FEATURE_NOT_SUPPORTED"; |
| 608 | case URI_TOO_LONG: |
| 609 | return "URI_TOO_LONG"; |
| 610 | case NODE_ALREADY_EXISTS: |
| 611 | return "NODE_ALREADY_EXISTS"; |
| 612 | case PERMISSION_DENIED: |
| 613 | return "PERMISSION_DENIED"; |
| 614 | case COMMAND_FAILED: |
| 615 | return "COMMAND_FAILED"; |
| 616 | case DATA_STORE_FAILURE: |
| 617 | return "DATA_STORE_FAILURE"; |
| 618 | case ROLLBACK_FAILED: |
| 619 | return "ROLLBACK_FAILED"; |
| 620 | |
| 621 | case REMOTE_ERROR: |
| 622 | return "REMOTE_ERROR"; |
| 623 | case METADATA_MISMATCH: |
| 624 | return "METADATA_MISMATCH"; |
| 625 | case INVALID_URI: |
| 626 | return "INVALID_URI"; |
| 627 | case CONCURRENT_ACCESS: |
| 628 | return "CONCURRENT_ACCESS"; |
| 629 | case ALERT_NOT_ROUTED: |
| 630 | return "ALERT_NOT_ROUTED"; |
| 631 | case TRANSACTION_ERROR: |
| 632 | return "TRANSACTION_ERROR"; |
| 633 | case SESSION_CREATION_TIMEOUT: |
| 634 | return "SESSION_CREATION_TIMEOUT"; |
| 635 | default: |
| 636 | return "<unknown code>"; |
| 637 | } |
| 638 | } |
| 639 | } |