diff src/org/tmatesoft/hg/core/HgCallbackTargetException.java @ 215:41a778e3fd31

Issue 5: Facilities for progress and cancellation. More specific exceptions. Exceptions from callbacks as RuntimeException
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 17 May 2011 00:56:54 +0200
parents
children c251bbc979cf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/tmatesoft/hg/core/HgCallbackTargetException.java	Tue May 17 00:56:54 2011 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011 TMate Software Ltd
+ *  
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For information on how to redistribute this software under
+ * the terms of a license other than GNU General Public License
+ * contact TMate Software at support@hg4j.com
+ */
+package org.tmatesoft.hg.core;
+
+import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION;
+
+import org.tmatesoft.hg.repo.HgRepository;
+import org.tmatesoft.hg.util.Path;
+
+/**
+ * Checked exception that indicates errors in client code and tries to supply extra information about the context it occured in.
+ * 
+ * @author Artem Tikhomirov
+ * @author TMate Software Ltd.
+ */
+@SuppressWarnings("serial")
+public class HgCallbackTargetException extends HgException {
+	private int revNumber = BAD_REVISION;
+	private Nodeid revision;
+	private Path filename;
+
+	/**
+	 * @param cause can't be <code>null</code>
+	 */
+	public HgCallbackTargetException(Throwable cause) {
+		super((Throwable) null);
+		if (cause == null) {
+			throw new IllegalArgumentException();
+		}
+		if (cause.getClass() == Wrap.class) {
+			// eliminate wrapper
+			initCause(cause.getCause());
+		} else {
+			initCause(cause);
+		}
+	}
+
+	/**
+	 * @return not {@link HgRepository#BAD_REVISION} only when local revision number was supplied at the construction time
+	 */
+	public int getRevisionNumber() {
+		return revNumber;
+	}
+
+	public HgCallbackTargetException setRevisionNumber(int rev) {
+		revNumber = rev;
+		return this;
+	}
+
+	/**
+	 * @return non-null only when revision was supplied at construction time
+	 */
+	public Nodeid getRevision() {
+		return revision;
+	}
+
+	public HgCallbackTargetException setRevision(Nodeid r) {
+		revision = r;
+		return this;
+	}
+
+	/**
+	 * @return non-null only if file name was set at construction time
+	 */
+	public Path getFileName() {
+		return filename;
+	}
+
+	public HgCallbackTargetException setFileName(Path name) {
+		filename = name;
+		return this;
+	}
+
+	@SuppressWarnings("unchecked")
+	public <T extends Exception> T getTargetException() {
+		return (T) getCause();
+	}
+	
+	/**
+	 * Despite this exception is merely a way to give users access to their own exceptions, it may still supply 
+	 * valuable debugging information about what led to the error.
+	 */
+	@Override
+	public String getMessage() {
+		StringBuilder sb = new StringBuilder();
+		if (filename != null) {
+			sb.append(filename);
+			sb.append(':');
+			sb.append(' ');
+		}
+		if (revNumber != BAD_REVISION) {
+			sb.append(revNumber);
+			if (revision != null) {
+				sb.append(':');
+			}
+		}
+		if (revision != null) {
+			sb.append(revision.shortNotation());
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 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 Wrap(Throwable cause) {
+			super(cause);
+			if (cause == null) {
+				throw new IllegalArgumentException();
+			}
+		}
+	}
+}