| // Copyright 2016 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package io.v.syncbase.exception; |
| |
| import java.util.NoSuchElementException; |
| import java.util.concurrent.CancellationException; |
| |
| import io.v.syncbase.core.VError; |
| import io.v.v23.verror.VException; |
| import io.v.v23.verror.VException.ActionCode; |
| |
| import static io.v.v23.verror.VException.ActionCode.fromValue; |
| |
| /** |
| * Utility for exception chaining. |
| */ |
| public final class Exceptions { |
| |
| private Exceptions() { |
| } |
| |
| private static String baseName(String v23ErrorId) { |
| String[] tokens = v23ErrorId.split("\\."); |
| int n = tokens.length; |
| if (n < 1) { |
| return v23ErrorId; |
| } |
| return tokens[n - 1]; |
| } |
| |
| private static void chainThrow(String message, String goErrorId, ActionCode action, Exception |
| cause) |
| throws SyncbaseException { |
| if (goErrorId == null) { |
| goErrorId = "null"; |
| } |
| String fullMessage = message + ": " + baseName(goErrorId); |
| switch (goErrorId) { |
| case "v.io/v23/verror.NotImplemented": |
| throw new UnsupportedOperationException(fullMessage, cause); |
| |
| case "v.io/v23/verror.EndOfFile": |
| throw new SyncbaseEndOfFileException(fullMessage, cause); |
| |
| case "v.io/v23/verror.BadArg": |
| case "v.io/v23/services/syncbase.InvalidName": |
| case "v.io/v23/services/syncbase.NotBoundToBatch": |
| case "v.io/v23/services/syncbase.ReadOnlyBatch": |
| throw new IllegalArgumentException(fullMessage, cause); |
| |
| case "v.io/v23/verror.Exist": |
| case "v.io/v23/services/syncbase.NotInDevMode": |
| case "v.io/v23/services/syncbase.BlobNotCommitted": |
| case "v.io/v23/services/syncbase.InvalidPermissionsChange": |
| case "v.io/v23/verror.Aborted": |
| throw new IllegalStateException(fullMessage, cause); |
| |
| case "v.io/v23/verror.NoExist": |
| throw withCause(new NoSuchElementException(fullMessage), cause); |
| |
| case "v.io/v23/verror.Unknown": |
| case "v.io/v23/verror.Internal": |
| case "v.io/v23/verror.BadState": |
| case "v.io/v23/verror.UnknownMethod": |
| case "v.io/v23/verror.UnknownSuffix": |
| case "v.io/v23/verror.BadProtocol": |
| case "v.io/v23/services/syncbase.BadExecStreamHeader": |
| throw new SyncbaseInternalException(fullMessage, cause); |
| |
| case "v.io/v23/verror.NoServers": |
| case "v.io/v23/services/syncbase.SyncgroupJoinFailed": |
| throw new SyncbaseNoServersException(fullMessage, cause); |
| |
| case "v.io/v23/verror.Canceled": |
| throw withCause(new CancellationException(fullMessage), cause); |
| |
| case "v.io/v23/verror.Timeout": |
| throw new SyncbaseRetryBackoffException(fullMessage, cause); |
| |
| case "v.io/v23/services/syncbase.CorruptDatabase": |
| throw new SyncbaseRestartException(fullMessage, cause); |
| |
| case "v.io/v23/verror.BadVersion": |
| case "v.io/v23/services/syncbase.ConcurrentBatch": |
| case "v.io/v23/services/syncbase.UnknownBatch": |
| throw new SyncbaseRaceException(fullMessage, cause); |
| |
| case "v.io/v23/verror.NoAccess": |
| case "v.io/v23/verror.NotTrusted": |
| case "v.io/v23/verror.NoExistOrNoAccess": |
| case "v.io/v23/services/syncbase.UnauthorizedCreateId": |
| case "v.io/v23/services/syncbase.InferAppBlessingFailed": |
| case "v.io/v23/services/syncbase.InferUserBlessingFailed": |
| case "v.io/v23/services/syncbase.InferDefaultPermsFailed": |
| throw new SyncbaseSecurityException(fullMessage, cause); |
| |
| default: |
| String fullerMessage = fullMessage + " (unexpected error ID " + goErrorId + ")"; |
| // See https://godoc.org/v.io/v23/verror#ActionCode |
| switch (action) { |
| case RETRY_REFETCH: |
| throw new SyncbaseRetryRefetchException(fullerMessage, cause); |
| case RETRY_BACKOFF: |
| throw new SyncbaseRetryBackoffException(fullerMessage, cause); |
| case RETRY_CONNECTION: |
| throw new SyncbaseRetryConnectionException(fullerMessage, cause); |
| case NO_RETRY: |
| default: |
| throw new SyncbaseInternalException(fullerMessage, cause); |
| } |
| } |
| } |
| |
| private static void chainThrow(String javaMessage, String goMessage, String v23ErrorId, |
| ActionCode action, Exception cause) throws SyncbaseException { |
| chainThrow("while " + javaMessage + " got error " + goMessage, v23ErrorId, action, cause); |
| } |
| |
| /** |
| * Throw an exception that wraps a low-level exception. |
| * |
| * @param javaMessage gives context from where the low-level exception was caught |
| * @param cause the low-level exception, possibly originating in native code |
| * @throws SyncbaseException always |
| */ |
| public static void chainThrow(String javaMessage, VError cause) throws SyncbaseException { |
| ActionCode action = fromValue((int) cause.actionCode); |
| chainThrow(javaMessage, cause.message, cause.id, action, cause); |
| } |
| |
| /** |
| * Throw an exception that wraps a low-level exception. |
| * |
| * @param javaMessage gives context from where the low-level exception was caught |
| * @param cause the low-level exception, possibly originating in native code |
| * @throws SyncbaseException always |
| */ |
| public static void chainThrow(String javaMessage, VException cause) throws SyncbaseException { |
| chainThrow(javaMessage, cause.getMessage(), cause.getID(), cause.getAction(), |
| cause); |
| } |
| |
| /** |
| * Throw an exception that wraps a low-level exception. |
| * |
| * @param doing what the high-level code was doing when the exception was caught |
| * @param name a Vanadoum name, i.e the name field of an Id object |
| * @param cause the low-level exception, possibly originating in native code |
| * @throws SyncbaseException always |
| */ |
| public static void chainThrow(String doing, String name, VError cause) throws |
| SyncbaseException { |
| chainThrow(doing + " " + name, cause); |
| } |
| |
| /** |
| * Throw an exception that wraps a low-level exception. |
| * |
| * @param doing what the high-level code was doing when the exception was caught |
| * @param name a Vanadoum name, i.e the name field of an Id object |
| * @param cause the low-level exception, possibly originating in native code |
| * @throws SyncbaseException always |
| */ |
| public static void chainThrow(String doing, String name, VException cause) throws |
| SyncbaseException { |
| chainThrow(doing + " " + name, cause); |
| } |
| |
| private static <T extends Exception> T withCause(T e, Exception cause) { |
| e.initCause(cause); |
| return e; |
| } |
| } |