# HG changeset patch # User Artem Tikhomirov # Date 1324510630 -10800 # Node ID a2341e761609ecd3c916ade3255c545af29be28d # Parent 091666b87f62db75817f3806d6fed860a90707ee Let callback implementations deliver errors (e,g. own exceptions) to client code diff -r 091666b87f62 -r a2341e761609 src/org/tmatesoft/hg/core/HgCallbackTargetException.java --- 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. diff -r 091666b87f62 -r a2341e761609 src/org/tmatesoft/hg/core/HgChangesetTreeHandler.java --- 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 { /** diff -r 091666b87f62 -r a2341e761609 src/org/tmatesoft/hg/core/HgLogCommand.java --- 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 {