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

com.google.appengine.api.datastore.DatastoreApiHelper Maven / Gradle / Ivy

There is a newer version: 2.0.32
Show newest version
/*
 * Copyright 2021 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
 *
 *     https://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.appengine.api.datastore;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.appidentity.AppIdentityService;
import com.google.appengine.api.appidentity.AppIdentityService.ParsedAppId;
import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
import com.google.appengine.api.utils.FutureWrapper;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.api.ApiProxy.ApiConfig;
import com.google.apphosting.datastore.DatastoreV3Pb.DatastoreService_3;
import com.google.apphosting.datastore.DatastoreV3Pb.Error;
import com.google.io.protocol.ProtocolMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.MessageLite;
import com.google.rpc.Code;
import java.util.ConcurrentModificationException;
import java.util.concurrent.Future;

/**
 * Helper methods and constants shared by classes that implement the Java api on top of the
 * datastore.
 *
 * 

Note: users should not access this class directly. * */ public final class DatastoreApiHelper { static final String DATASTORE_V3_PACKAGE = "datastore_v3"; /** * Key to put in {@link ApiProxy.Environment#getAttributes()} to override the app id used by the * datastore api. If absent, {@link ApiProxy.Environment#getAppId()} will be used. */ @SuppressWarnings("javadoc") static final String APP_ID_OVERRIDE_KEY = "com.google.appengine.datastore.AppIdOverride"; private static final AppIdentityService appIdentityService = AppIdentityServiceFactory.getAppIdentityService(); private DatastoreApiHelper() {} // Corresponds to _ToDatastoreError in datastore.py. // Keep in sync! public static RuntimeException translateError(ApiProxy.ApplicationException exception) { Error.ErrorCode errorCode = Error.ErrorCode.valueOf(exception.getApplicationError()); if (errorCode == null) { return new DatastoreFailureException(exception.getErrorDetail()); } switch (errorCode) { case BAD_REQUEST: return new IllegalArgumentException(exception.getErrorDetail()); case CONCURRENT_TRANSACTION: return new ConcurrentModificationException(exception.getErrorDetail()); case NEED_INDEX: return new DatastoreNeedIndexException(exception.getErrorDetail()); case TIMEOUT: case BIGTABLE_ERROR: return new DatastoreTimeoutException(exception.getErrorDetail()); case COMMITTED_BUT_STILL_APPLYING: return new CommittedButStillApplyingException(exception.getErrorDetail()); case RESOURCE_EXHAUSTED: return new ApiProxy.OverQuotaException(exception.getErrorDetail(), (Throwable) null); case INTERNAL_ERROR: default: return new DatastoreFailureException(exception.getErrorDetail()); } } static RuntimeException createV1Exception(Code code, String message, Throwable cause) { if (code == null) { return new DatastoreFailureException(message, cause); } switch (code) { case ABORTED: return new ConcurrentModificationException(message, cause); case FAILED_PRECONDITION: if (message.contains("The Cloud Datastore API is not enabled for the project")) { return new DatastoreFailureException(message, cause); } // Could also indicate ErrorCode.SAFE_TIME_TOO_OLD. return new DatastoreNeedIndexException(message, cause); case DEADLINE_EXCEEDED: return new DatastoreTimeoutException(message, cause); case INVALID_ARGUMENT: case PERMISSION_DENIED: return new IllegalArgumentException(message, cause); case UNAVAILABLE: return new ApiProxy.RPCFailedException(message, cause); case RESOURCE_EXHAUSTED: return new ApiProxy.OverQuotaException(message, cause); case INTERNAL: // Could also indicate ErrorCode.COMMITTED_BUT_STILL_APPLYING. default: return new DatastoreFailureException(message, cause); } } static > Future makeAsyncCall( ApiConfig apiConfig, final DatastoreService_3.Method method, MessageLite request, final T responseProto) { Future response = ApiProxy.makeAsyncCall( DATASTORE_V3_PACKAGE, method.name(), request.toByteArray(), apiConfig); return new FutureWrapper(response) { @Override protected T wrap(byte[] responseBytes) throws InvalidProtocolBufferException { // This null check is mainly for the benefit of unit tests // (specifically ones using EasyMock, where the default behavior // is to return null). if (responseBytes != null && responseProto != null) { if (!responseProto.parseFrom(responseBytes)) { throw new InvalidProtocolBufferException( String.format("Invalid %s.%s response", DATASTORE_V3_PACKAGE, method.name())); } String initializationError = responseProto.findInitializationError(); if (initializationError != null) { throw new InvalidProtocolBufferException(initializationError); } } return responseProto; } @Override protected Throwable convertException(Throwable cause) { if (cause instanceof ApiProxy.ApplicationException) { return translateError((ApiProxy.ApplicationException) cause); } return cause; } }; } static String getCurrentProjectId() { return toProjectId(getCurrentAppId()); } static String toProjectId(String appId) { ParsedAppId parsedAppId = appIdentityService.parseFullAppId(appId); if (parsedAppId.getDomain().isEmpty()) { return parsedAppId.getId(); } else { return String.format("%s:%s", parsedAppId.getDomain(), parsedAppId.getId()); } } static String getCurrentAppId() { ApiProxy.Environment environment = DatastoreServiceGlobalConfig.getCurrentApiProxyEnvironment(); if (environment == null) { throw new NullPointerException("No API environment is registered for this thread."); } Object appIdOverride = environment.getAttributes().get(APP_ID_OVERRIDE_KEY); if (appIdOverride != null) { // We'll just let the ClassCastException occur if someone put bad data in the Environment. return (String) appIdOverride; } return environment.getAppId(); } /** * Returns a new {@link AppIdNamespace} with the current appId and the namespace registered with * the {@link NamespaceManager} */ static AppIdNamespace getCurrentAppIdNamespace() { return getCurrentAppIdNamespace(getCurrentAppId()); } /** * Returns a new {@link AppIdNamespace} with the namespace currently registered with the {@link * NamespaceManager} for a given appid. */ static AppIdNamespace getCurrentAppIdNamespace(String appId) { String namespace = NamespaceManager.get(); namespace = namespace == null ? "" : namespace; return new AppIdNamespace(appId, namespace); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy