comparison src/org/tmatesoft/hg/core/HgCallbackTargetException.java @ 423:9c9c442b5f2e

Major refactoring of exception handling. Low-level API uses RuntimeExceptions, while checked are left for higher level
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Fri, 23 Mar 2012 22:51:18 +0100
parents 2747b0723867
children 31a89587eb04
comparison
equal deleted inserted replaced
422:5d1cc7366d04 423:9c9c442b5f2e
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.core; 17 package org.tmatesoft.hg.core;
18 18
19 import org.tmatesoft.hg.internal.ExceptionInfo;
19 import org.tmatesoft.hg.util.Path; 20 import org.tmatesoft.hg.util.Path;
20 21
21 22
22 23
23 /** 24 /**
24 * Checked exception that indicates errors in client code and tries to supply extra information about the context it occurred in. 25 * Checked exception that client supplied callback code can use to indicates its own errors.
25 * 26 *
26 * Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply. 27 * <p>Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply.
27 * However, there's no straightforward way to alter throws clause for these methods, and alternatives like generic {@link Exception} or 28 * However, there's no straightforward way to alter throws clause for these methods, and alternatives like generic {@link Exception} or
28 * library's own {@link HgException} are rather obscure. Suggested approach is to wrap whatever exception user code produces with 29 * library's own {@link HgException} are rather obscure. Suggested approach is to wrap whatever exception user code produces with
29 * {@link RuntimeException} subclass, {@link Wrap}. Then, unwrap and re-throw with checked {@link HgCallbackTargetException}. 30 * {@link HgCallbackTargetException}, the only checked exception allowed out from a callback.
30 * 31 *
31 * FIXME REVISIT perhaps, shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all? 32 * <p>It's intentionally not a subclass of {@link HgException} to avoid get mixed with library own errors and be processed separately.
32 * FIXME decide whether shall root at HgException ("throws HgException, HgCallbackTargetException" looks a bit odd now) 33 *
34 * FIXME REVISIT shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all.
33 * 35 *
34 * @author Artem Tikhomirov 36 * @author Artem Tikhomirov
35 * @author TMate Software Ltd. 37 * @author TMate Software Ltd.
36 */ 38 */
37 @SuppressWarnings("serial") 39 @SuppressWarnings("serial")
38 public class HgCallbackTargetException extends HgException { 40 public class HgCallbackTargetException extends Exception {
41
42 protected final ExceptionInfo<HgCallbackTargetException> details = new ExceptionInfo<HgCallbackTargetException>(this);
43
39 /** 44 /**
40 * @param cause can't be <code>null</code> 45 * @param cause can't be <code>null</code>
41 */ 46 */
42 public HgCallbackTargetException(Throwable cause) { 47 public HgCallbackTargetException(Throwable cause) {
43 super((String) null); 48 super((String) null);
44 if (cause == null) { 49 if (cause == null) {
45 throw new IllegalArgumentException(); 50 throw new IllegalArgumentException();
46 } 51 }
47 if (cause.getClass() == Wrap.class) { 52 initCause(cause);
48 // eliminate wrapper
49 initCause(cause.getCause());
50 } else {
51 initCause(cause);
52 }
53 } 53 }
54 54
55 @SuppressWarnings("unchecked") 55 @SuppressWarnings("unchecked")
56 public <T extends Exception> T getTargetException() { 56 public <T extends Throwable> T getTargetException() {
57 return (T) getCause(); 57 return (T) getCause();
58 } 58 }
59 59
60 /** 60 /**
61 * Despite this exception is merely a way to give users access to their own exceptions, it may still supply 61 * Despite this exception is merely a way to give users access to their own exceptions, it may still supply
62 * valuable debugging information about what led to the error. 62 * valuable debugging information about what led to the error.
63 */ 63 */
64 @Override 64 @Override
65 public String getMessage() { 65 public String getMessage() {
66 StringBuilder sb = new StringBuilder(); 66 StringBuilder sb = new StringBuilder();
67 sb.append("Original exception thrown: "); 67 sb.append("Error from callback. Original exception thrown: ");
68 sb.append(getCause().getClass().getName()); 68 sb.append(getCause().getClass().getName());
69 sb.append(" at "); 69 sb.append(" at ");
70 extras.appendDetails(sb); 70 details.appendDetails(sb);
71 return sb.toString(); 71 return sb.toString();
72 } 72 }
73 73
74 @Override
75 public HgCallbackTargetException setRevision(Nodeid r) { 74 public HgCallbackTargetException setRevision(Nodeid r) {
76 return (HgCallbackTargetException) super.setRevision(r); 75 return details.setRevision(r);
77 }
78 @Override
79 public HgCallbackTargetException setRevisionIndex(int rev) {
80 return (HgCallbackTargetException) super.setRevisionIndex(rev);
81 }
82 @Override
83 public HgCallbackTargetException setFileName(Path name) {
84 return (HgCallbackTargetException) super.setFileName(name);
85 } 76 }
86 77
87 /** 78 public HgCallbackTargetException setRevisionIndex(int rev) {
88 * Given the approach high-level handlers throw RuntimeExceptions to indicate errors, and 79 return details.setRevisionIndex(rev);
89 * a need to throw reasonable checked exception from client code, clients may utilize this class 80 }
90 * to get their checked exceptions unwrapped by {@link HgCallbackTargetException} and serve as that
91 * exception cause, eliminating {@link RuntimeException} mediator.
92 */
93 public static final class Wrap extends RuntimeException {
94 81
95 public Wrap(Throwable cause) { 82 public HgCallbackTargetException setFileName(Path name) {
96 super(cause); 83 return details.setFileName(name);
97 if (cause == null) {
98 throw new IllegalArgumentException();
99 }
100 }
101 } 84 }
102 } 85 }