tikhomirov@215: /* tikhomirov@215: * Copyright (c) 2011 TMate Software Ltd tikhomirov@215: * tikhomirov@215: * This program is free software; you can redistribute it and/or modify tikhomirov@215: * it under the terms of the GNU General Public License as published by tikhomirov@215: * the Free Software Foundation; version 2 of the License. tikhomirov@215: * tikhomirov@215: * This program is distributed in the hope that it will be useful, tikhomirov@215: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@215: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@215: * GNU General Public License for more details. tikhomirov@215: * tikhomirov@215: * For information on how to redistribute this software under tikhomirov@215: * the terms of a license other than GNU General Public License tikhomirov@215: * contact TMate Software at support@hg4j.com tikhomirov@215: */ tikhomirov@215: package org.tmatesoft.hg.core; tikhomirov@215: tikhomirov@215: import static org.tmatesoft.hg.repo.HgRepository.BAD_REVISION; tikhomirov@215: tikhomirov@215: import org.tmatesoft.hg.repo.HgRepository; tikhomirov@215: import org.tmatesoft.hg.util.Path; tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * Checked exception that indicates errors in client code and tries to supply extra information about the context it occured in. tikhomirov@215: * tikhomirov@215: * @author Artem Tikhomirov tikhomirov@215: * @author TMate Software Ltd. tikhomirov@215: */ tikhomirov@215: @SuppressWarnings("serial") tikhomirov@215: public class HgCallbackTargetException extends HgException { tikhomirov@215: private int revNumber = BAD_REVISION; tikhomirov@215: private Nodeid revision; tikhomirov@215: private Path filename; tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * @param cause can't be null tikhomirov@215: */ tikhomirov@215: public HgCallbackTargetException(Throwable cause) { tikhomirov@215: super((Throwable) null); tikhomirov@215: if (cause == null) { tikhomirov@215: throw new IllegalArgumentException(); tikhomirov@215: } tikhomirov@215: if (cause.getClass() == Wrap.class) { tikhomirov@215: // eliminate wrapper tikhomirov@215: initCause(cause.getCause()); tikhomirov@215: } else { tikhomirov@215: initCause(cause); tikhomirov@215: } tikhomirov@215: } tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * @return not {@link HgRepository#BAD_REVISION} only when local revision number was supplied at the construction time tikhomirov@215: */ tikhomirov@215: public int getRevisionNumber() { tikhomirov@215: return revNumber; tikhomirov@215: } tikhomirov@215: tikhomirov@215: public HgCallbackTargetException setRevisionNumber(int rev) { tikhomirov@215: revNumber = rev; tikhomirov@215: return this; tikhomirov@215: } tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * @return non-null only when revision was supplied at construction time tikhomirov@215: */ tikhomirov@215: public Nodeid getRevision() { tikhomirov@215: return revision; tikhomirov@215: } tikhomirov@215: tikhomirov@215: public HgCallbackTargetException setRevision(Nodeid r) { tikhomirov@215: revision = r; tikhomirov@215: return this; tikhomirov@215: } tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * @return non-null only if file name was set at construction time tikhomirov@215: */ tikhomirov@215: public Path getFileName() { tikhomirov@215: return filename; tikhomirov@215: } tikhomirov@215: tikhomirov@215: public HgCallbackTargetException setFileName(Path name) { tikhomirov@215: filename = name; tikhomirov@215: return this; tikhomirov@215: } tikhomirov@215: tikhomirov@215: @SuppressWarnings("unchecked") tikhomirov@215: public T getTargetException() { tikhomirov@215: return (T) getCause(); tikhomirov@215: } tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * Despite this exception is merely a way to give users access to their own exceptions, it may still supply tikhomirov@215: * valuable debugging information about what led to the error. tikhomirov@215: */ tikhomirov@215: @Override tikhomirov@215: public String getMessage() { tikhomirov@215: StringBuilder sb = new StringBuilder(); tikhomirov@215: if (filename != null) { tikhomirov@215: sb.append(filename); tikhomirov@215: sb.append(':'); tikhomirov@215: sb.append(' '); tikhomirov@215: } tikhomirov@215: if (revNumber != BAD_REVISION) { tikhomirov@215: sb.append(revNumber); tikhomirov@215: if (revision != null) { tikhomirov@215: sb.append(':'); tikhomirov@215: } tikhomirov@215: } tikhomirov@215: if (revision != null) { tikhomirov@215: sb.append(revision.shortNotation()); tikhomirov@215: } tikhomirov@215: return sb.toString(); tikhomirov@215: } tikhomirov@215: tikhomirov@215: /** tikhomirov@215: * Given the approach high-level handlers throw RuntimeExceptions to indicate errors, and tikhomirov@215: * a need to throw reasonable checked exception from client code, clients may utilize this class tikhomirov@215: * to get their checked exceptions unwrapped by {@link HgCallbackTargetException} and serve as that tikhomirov@215: * exception cause, eliminating {@link RuntimeException} mediator. tikhomirov@215: */ tikhomirov@215: public static final class Wrap extends RuntimeException { tikhomirov@215: tikhomirov@215: public Wrap(Throwable cause) { tikhomirov@215: super(cause); tikhomirov@215: if (cause == null) { tikhomirov@215: throw new IllegalArgumentException(); tikhomirov@215: } tikhomirov@215: } tikhomirov@215: } tikhomirov@215: }