diff 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
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCallbackTargetException.java	Fri Mar 23 21:26:01 2012 +0100
+++ b/src/org/tmatesoft/hg/core/HgCallbackTargetException.java	Fri Mar 23 22:51:18 2012 +0100
@@ -16,26 +16,31 @@
  */
 package org.tmatesoft.hg.core;
 
+import org.tmatesoft.hg.internal.ExceptionInfo;
 import org.tmatesoft.hg.util.Path;
 
 
 
 /**
- * Checked exception that indicates errors in client code and tries to supply extra information about the context it occurred in.
+ * Checked exception that client supplied callback code can use to indicates its own errors.
  * 
- * Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply. 
+ * <p>Generally, client need to pass own error information/exceptions from within implementations of the callback methods they supply. 
  * However, there's no straightforward way to alter throws clause for these methods, and alternatives like generic {@link Exception} or
  * library's own {@link HgException} are rather obscure. Suggested approach is to wrap whatever exception user code produces with
- * {@link RuntimeException} subclass, {@link Wrap}. Then, unwrap and re-throw with checked {@link HgCallbackTargetException}. 
+ * {@link HgCallbackTargetException}, the only checked exception allowed out from a callback.
  * 
- * FIXME REVISIT perhaps, shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all?
- * FIXME decide whether shall root at HgException ("throws HgException, HgCallbackTargetException" looks a bit odd now) 
+ *  <p>It's intentionally not a subclass of {@link HgException} to avoid get mixed with library own errors and be processed separately.
+ * 
+ * FIXME REVISIT shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all.
  * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
  */
 @SuppressWarnings("serial")
-public class HgCallbackTargetException extends HgException {
+public class HgCallbackTargetException extends Exception {
+	
+	protected final ExceptionInfo<HgCallbackTargetException> details = new ExceptionInfo<HgCallbackTargetException>(this);
+
 	/**
 	 * @param cause can't be <code>null</code>
 	 */
@@ -44,16 +49,11 @@
 		if (cause == null) {
 			throw new IllegalArgumentException();
 		}
-		if (cause.getClass() == Wrap.class) {
-			// eliminate wrapper
-			initCause(cause.getCause());
-		} else {
-			initCause(cause);
-		}
+		initCause(cause);
 	}
 
 	@SuppressWarnings("unchecked")
-	public <T extends Exception> T getTargetException() {
+	public <T extends Throwable> T getTargetException() {
 		return (T) getCause();
 	}
 	
@@ -64,39 +64,22 @@
 	@Override
 	public String getMessage() {
 		StringBuilder sb = new StringBuilder();
-		sb.append("Original exception thrown: ");
+		sb.append("Error from callback. Original exception thrown: ");
 		sb.append(getCause().getClass().getName());
 		sb.append(" at ");
-		extras.appendDetails(sb);
+		details.appendDetails(sb);
 		return sb.toString();
 	}
 
-	@Override
 	public HgCallbackTargetException setRevision(Nodeid r) {
-		return (HgCallbackTargetException) super.setRevision(r);
-	}
-	@Override
-	public HgCallbackTargetException setRevisionIndex(int rev) {
-		return (HgCallbackTargetException) super.setRevisionIndex(rev);
-	}
-	@Override
-	public HgCallbackTargetException setFileName(Path name) {
-		return (HgCallbackTargetException) super.setFileName(name);
+		return details.setRevision(r);
 	}
 
-	/**
-	 * Given the approach high-level handlers throw RuntimeExceptions to indicate errors, and
-	 * a need to throw reasonable checked exception from client code, clients may utilize this class
-	 * to get their checked exceptions unwrapped by {@link HgCallbackTargetException} and serve as that 
-	 * exception cause, eliminating {@link RuntimeException} mediator.
-	 */
-	public static final class Wrap extends RuntimeException {
+	public HgCallbackTargetException setRevisionIndex(int rev) {
+		return details.setRevisionIndex(rev);
+	}
 
-		public Wrap(Throwable cause) {
-			super(cause);
-			if (cause == null) {
-				throw new IllegalArgumentException();
-			}
-		}
+	public HgCallbackTargetException setFileName(Path name) {
+		return details.setFileName(name);
 	}
 }