com.google.gcloud.datastore.DatastoreServiceException.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gcloud.datastore.DatastoreServiceException.java

Source

/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * 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.gcloud.datastore;

import com.google.api.services.datastore.client.DatastoreException;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableMap;
import com.google.gcloud.RetryHelper;
import com.google.gcloud.RetryHelper.RetryHelperException;

import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import java.util.HashMap;
import java.util.Map;

public class DatastoreServiceException extends RuntimeException {

    private static final long serialVersionUID = 8170357898917041899L;
    private static final ImmutableMap<String, Code> REASON_TO_CODE;
    private static final ImmutableMap<Integer, Code> HTTP_TO_CODE;

    private final Code code;

    /**
     * An error code to represent the failure.
     *
     * @see <a href="https://cloud.google.com/datastore/docs/concepts/errors#Error_Codes">Google Cloud Datastore error codes</a>
     */
    public enum Code {

        ABORTED(true, "Request aborted", 409), DEADLINE_EXCEEDED(true, "Deadline exceeded", 403), UNAVAILABLE(true,
                "Could not reach service", 503), FAILED_PRECONDITION(false, "Invalid request",
                        412), INVALID_ARGUMENT(false, "Request parameter has an invalid value",
                                400), PERMISSION_DENIED(false, "Unauthorized request", 403), UNAUTHORIZED(false,
                                        "Unauthorized", 401), RESOURCE_EXHAUSTED(false, "Quota exceeded",
                                                402), INTERNAL(false, "Server returned an error",
                                                        500), UNKNOWN(false, "Unknown failure", -1);

        private final boolean retriable;
        private final String message;
        private final int httpCode;

        Code(boolean retriable, String message, int httpCode) {
            this.retriable = retriable;
            this.message = message;
            this.httpCode = httpCode;
        }

        public Integer httpCode() {
            return httpCode;
        }

        /**
         * Returns {@code true} if this exception is transient and the same request could be retried.
         * For any retry it is highly recommended to apply an exponential backoff.
         */
        public boolean isRetriable() {
            return retriable;
        }

        DatastoreServiceException translate(DatastoreException exception, String message) {
            return new DatastoreServiceException(this, message, exception);
        }
    }

    static {
        ImmutableMap.Builder<String, Code> builder = ImmutableMap.builder();
        Map<Integer, Code> httpCodes = new HashMap<>();
        for (Code code : Code.values()) {
            builder.put(code.name(), code);
            httpCodes.put(code.httpCode(), code);
        }
        REASON_TO_CODE = builder.build();
        HTTP_TO_CODE = ImmutableMap.copyOf(httpCodes);
    }

    public DatastoreServiceException(Code code, String message, Exception cause) {
        super(MoreObjects.firstNonNull(message, code.message), cause);
        this.code = code;
    }

    public DatastoreServiceException(Code code, String message) {
        this(code, message, null);
    }

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

    static DatastoreServiceException translateAndThrow(RetryHelperException ex) {
        if (ex.getCause() instanceof DatastoreException) {
            return translateAndThrow((DatastoreException) ex.getCause());
        }
        if (ex instanceof RetryHelper.RetryInterruptedException) {
            RetryHelper.RetryInterruptedException.propagate();
        }
        throw new DatastoreServiceException(Code.UNKNOWN, ex.getMessage(), ex);
    }

    /**
     * Translate DatastoreException to DatastoreServiceException based on their
     * HTTP error codes. This method will always throw a new DatastoreServiceException.
     *
     * @throws DatastoreServiceException every time
     */
    static DatastoreServiceException translateAndThrow(DatastoreException exception) {
        String message = exception.getMessage();
        String reason = "";
        if (message != null) {
            try {
                JSONObject json = new JSONObject(new JSONTokener(message));
                JSONObject error = json.getJSONObject("error").getJSONArray("errors").getJSONObject(0);
                reason = error.getString("reason");
                message = error.getString("message");
            } catch (JSONException ignore) {
                // ignore - will be converted to unknown
            }
        }
        Code code = REASON_TO_CODE.get(reason);
        if (code == null) {
            code = MoreObjects.firstNonNull(HTTP_TO_CODE.get(exception.getCode()), Code.UNKNOWN);
        }
        throw code.translate(exception, message);
    }

    /**
     * Throw a DatastoreServiceException with {@code FAILED_PRECONDITION} code and the {@code message}
     * in a nested exception.
     *
     * @throws DatastoreServiceException every time
     */
    static DatastoreServiceException throwInvalidRequest(String massage, Object... params) {
        throw new DatastoreServiceException(Code.FAILED_PRECONDITION, String.format(massage, params));
    }
}