changeset 370:a2341e761609

Let callback implementations deliver errors (e,g. own exceptions) to client code
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 22 Dec 2011 02:37:10 +0300
parents 091666b87f62
children aa2e589d4e84
files src/org/tmatesoft/hg/core/HgCallbackTargetException.java src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java src/org/tmatesoft/hg/core/HgLogCommand.java
diffstat 3 files changed, 41 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/core/HgCallbackTargetException.java	Thu Dec 22 01:46:40 2011 +0300
+++ b/src/org/tmatesoft/hg/core/HgCallbackTargetException.java	Thu Dec 22 02:37:10 2011 +0300
@@ -21,7 +21,14 @@
 
 
 /**
- * Checked exception that indicates errors in client code and tries to supply extra information about the context it occured in.
+ * Checked exception that indicates errors in client code and tries to supply extra information about the context it occurred in.
+ * 
+ * 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}. 
+ * 
+ * FIXME REVISIT perhaps, shall just throw HgCallbackTargetException from any handler, and do not catch anything in commands at all?
  * 
  * @author Artem Tikhomirov
  * @author TMate Software Ltd.
--- a/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java	Thu Dec 22 01:46:40 2011 +0300
+++ b/src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java	Thu Dec 22 02:37:10 2011 +0300
@@ -29,9 +29,11 @@
 public interface HgChangesetTreeHandler {
 	/**
 	 * @param entry access to various pieces of information about current tree node. Instances might be 
-	 * reused across calls and shall not be kept by client's code 
+	 * reused across calls and shall not be kept by client's code
+	 * @throws HgCallbackTargetException.Wrap wrapper object for any exception user code may produce. Wrapped exception would get re-thrown with {@link HgCallbackTargetException} 
+	 * @throws CancelledException FIXME 
 	 */
-	public void next(HgChangesetTreeHandler.TreeElement entry) throws CancelledException;
+	public void next(HgChangesetTreeHandler.TreeElement entry) throws HgCallbackTargetException.Wrap, CancelledException;
 
 	interface TreeElement {
 		/**
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java	Thu Dec 22 01:46:40 2011 +0300
+++ b/src/org/tmatesoft/hg/core/HgLogCommand.java	Thu Dec 22 02:37:10 2011 +0300
@@ -203,10 +203,13 @@
 	/**
 	 * 
 	 * @param handler callback to process changesets.
+	 * @throws HgCallbackTargetException FIXME
+	 * @throws HgException FIXME
+	 * @throws CancelledException FIXME
 	 * @throws IllegalArgumentException when inspector argument is null
 	 * @throws ConcurrentModificationException if this log command instance is already running
 	 */
-	public void execute(HgChangesetHandler handler) throws HgDataStreamException, HgInvalidControlFileException, HgCallbackTargetException, CancelledException {
+	public void execute(HgChangesetHandler handler) throws HgCallbackTargetException, HgException, CancelledException {
 		if (handler == null) {
 			throw new IllegalArgumentException();
 		}
@@ -237,7 +240,7 @@
 							HgFileRevision dst = new HgFileRevision(repo, fileNode.getRevision(0), fileNode.getPath(), src.getPath());
 							try {
 								((FileHistoryHandler) handler).copy(src, dst);
-							} catch (RuntimeException ex) {
+							} catch (HgCallbackTargetException.Wrap ex) {
 								throw new HgCallbackTargetException(ex).setRevision(fileNode.getCopySourceRevision()).setFileName(fileNode.getCopySourceName());
 							}
 						}
@@ -259,7 +262,14 @@
 		}
 	}
 	
-	public void execute(HgChangesetTreeHandler handler) throws CancelledException, HgException {
+	/**
+	 * 
+	 * @param handler
+	 * @throws HgCallbackTargetException
+	 * @throws HgException
+	 * @throws CancelledException
+	 */
+	public void execute(HgChangesetTreeHandler handler) throws HgCallbackTargetException, HgException, CancelledException {
 		if (handler == null) {
 			throw new IllegalArgumentException();
 		}
@@ -318,13 +328,17 @@
 		} else {
 			ph2 = new ProgressSupport.Sub(progressHelper, 3);
 		}
-		ph2.start(completeHistory.length);
-		// XXX shall sort completeHistory according to changeset numbers?
-		for (int i = 0; i < completeHistory.length; i++ ) {
-			final HistoryNode n = completeHistory[i];
-			handler.next(ei.init(n));
-			ph2.worked(1);
-			cancelHelper.checkCancelled();
+		try {
+			ph2.start(completeHistory.length);
+			// XXX shall sort completeHistory according to changeset numbers?
+			for (int i = 0; i < completeHistory.length; i++ ) {
+				final HistoryNode n = completeHistory[i];
+				handler.next(ei.init(n));
+				ph2.worked(1);
+				cancelHelper.checkCancelled();
+			}
+		} catch (HgCallbackTargetException.Wrap ex) {
+			throw new HgCallbackTargetException(ex);
 		}
 		progressHelper.done();
 	}
@@ -379,9 +393,12 @@
 	 * @author Artem Tikhomirov
 	 * @author TMate Software Ltd.
 	 */
-	public interface FileHistoryHandler extends HgChangesetHandler {
+	public interface FileHistoryHandler extends HgChangesetHandler { // FIXME move to stanalone class file, perhaps?
 		// XXX perhaps, should distinguish copy from rename? And what about merged revisions and following them?
-		void copy(HgFileRevision from, HgFileRevision to);
+		/**
+		 * @throws HgCallbackTargetException.Wrap wrapper object for any exception user code may produce. Wrapped exception would get re-thrown with {@link HgCallbackTargetException} 
+		 */
+		void copy(HgFileRevision from, HgFileRevision to) throws HgCallbackTargetException.Wrap;
 	}
 	
 	public static class CollectHandler implements HgChangesetHandler {