All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.cloud.spanner.SpannerException Maven / Gradle / Ivy

There is a newer version: 6.81.1
Show newest version
/*
 * Copyright 2017 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.cloud.spanner;

import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.ErrorDetails;
import com.google.cloud.grpc.BaseGrpcServiceException;
import com.google.common.base.Preconditions;
import com.google.protobuf.util.Durations;
import com.google.rpc.ResourceInfo;
import com.google.rpc.RetryInfo;
import io.grpc.Metadata;
import io.grpc.Status;
import io.grpc.protobuf.ProtoUtils;
import java.util.Map;
import javax.annotation.Nullable;

/** Base exception type for all exceptions produced by the Cloud Spanner service. */
public class SpannerException extends BaseGrpcServiceException {
  /** Base exception type for NOT_FOUND exceptions for known resource types. */
  public abstract static class ResourceNotFoundException extends SpannerException {
    private final ResourceInfo resourceInfo;

    ResourceNotFoundException(
        DoNotConstructDirectly token,
        @Nullable String message,
        ResourceInfo resourceInfo,
        @Nullable Throwable cause,
        @Nullable ApiException apiException) {
      super(token, ErrorCode.NOT_FOUND, /* retryable */ false, message, cause, apiException);
      this.resourceInfo = resourceInfo;
    }

    public String getResourceName() {
      return resourceInfo.getResourceName();
    }
  }

  private static final long serialVersionUID = 20150916L;
  private static final Metadata.Key KEY_RETRY_INFO =
      ProtoUtils.keyForProto(RetryInfo.getDefaultInstance());

  private final ErrorCode code;
  private final ApiException apiException;

  /** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
  SpannerException(
      DoNotConstructDirectly token,
      ErrorCode code,
      boolean retryable,
      @Nullable String message,
      @Nullable Throwable cause) {
    this(token, code, retryable, message, cause, null);
  }

  /** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
  SpannerException(
      DoNotConstructDirectly token,
      ErrorCode code,
      boolean retryable,
      @Nullable String message,
      @Nullable Throwable cause,
      @Nullable ApiException apiException) {
    super(message, cause, code.getCode(), retryable);
    if (token != DoNotConstructDirectly.ALLOWED) {
      throw new AssertionError("Do not construct directly: use SpannerExceptionFactory");
    }
    this.code = Preconditions.checkNotNull(code);
    this.apiException = apiException;
  }

  /** Returns the error code associated with this exception. */
  public ErrorCode getErrorCode() {
    return code;
  }

  enum DoNotConstructDirectly {
    ALLOWED
  }

  /**
   * Return the retry delay for operation in milliseconds. Return -1 if this does not specify any
   * retry delay.
   */
  public long getRetryDelayInMillis() {
    return extractRetryDelay(this.getCause());
  }

  static long extractRetryDelay(Throwable cause) {
    if (cause != null) {
      Metadata trailers = Status.trailersFromThrowable(cause);
      if (trailers != null && trailers.containsKey(KEY_RETRY_INFO)) {
        RetryInfo retryInfo = trailers.get(KEY_RETRY_INFO);
        if (retryInfo.hasRetryDelay()) {
          return Durations.toMillis(retryInfo.getRetryDelay());
        }
      }
    }
    return -1L;
  }

  /**
   * Checks the underlying reason of the exception and if it's {@link ApiException} then return the
   * reason otherwise null.
   *
   * @see Reason
   * @return the reason of an error.
   */
  public String getReason() {
    if (this.apiException != null) {
      return this.apiException.getReason();
    }
    return null;
  }

  /**
   * Checks the underlying reason of the exception and if it's {@link ApiException} then return the
   * specific domain otherwise null.
   *
   * @see Domain
   * @return the logical grouping to which the "reason" belongs.
   */
  public String getDomain() {
    if (this.apiException != null) {
      return this.apiException.getDomain();
    }
    return null;
  }

  /**
   * Checks the underlying reason of the exception and if it's {@link ApiException} then return a
   * map of key-value pairs otherwise null.
   *
   * @see Metadata
   * @return the map of additional structured details about an error.
   */
  public Map getMetadata() {
    if (this.apiException != null) {
      return this.apiException.getMetadata();
    }
    return null;
  }

  /**
   * Checks the underlying reason of the exception and if it's {@link ApiException} then return the
   * ErrorDetails otherwise null.
   *
   * @see Status
   * @see Error
   *     Details
   * @return An object containing getters for structured objects from error_details.proto.
   */
  public ErrorDetails getErrorDetails() {
    if (this.apiException != null) {
      return this.apiException.getErrorDetails();
    }
    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy