Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / DatastoreApiHelper.java
blob60d1e841e920afe1c935f540ddb6146c32661a04
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 package com.google.appengine.api.datastore;
4 import com.google.appengine.api.NamespaceManager;
5 import com.google.appengine.api.appidentity.AppIdentityService;
6 import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
7 import com.google.appengine.api.utils.FutureWrapper;
8 import com.google.apphosting.api.ApiProxy;
9 import com.google.apphosting.api.ApiProxy.ApiConfig;
10 import com.google.apphosting.datastore.DatastoreV3Pb.DatastoreService_3;
11 import com.google.apphosting.datastore.DatastoreV3Pb.Error;
12 import com.google.datastore.v1beta3.Datastore;
13 import com.google.io.protocol.ProtocolMessage;
14 import com.google.protobuf.MessageLite;
15 import com.google.protobuf.Parser;
17 import java.util.ConcurrentModificationException;
18 import java.util.concurrent.Future;
20 /**
21 * Helper methods and constants shared by classes that implement the Java api
22 * on top of the datastore.
24 * <p>Note: users should not access this class directly.
27 public final class DatastoreApiHelper {
29 static final String DATASTORE_V3_PACKAGE = "datastore_v3";
30 static final String CLOUD_DATASTORE_V1_PACKAGE = "cloud_datastore_v1";
32 /**
33 * Key to put in {@link ApiProxy.Environment#getAttributes()} to override the app id used by the
34 * datastore api. If absent, {@link ApiProxy.Environment#getAppId()} will be used.
36 @SuppressWarnings("javadoc")
37 static final String APP_ID_OVERRIDE_KEY = "com.google.appengine.datastore.AppIdOverride";
39 private static final AppIdentityService appIdentityService =
40 AppIdentityServiceFactory.getAppIdentityService();
42 private DatastoreApiHelper() {}
44 public static RuntimeException translateError(ApiProxy.ApplicationException exception) {
45 Error.ErrorCode errorCode = Error.ErrorCode.valueOf(exception.getApplicationError());
46 if (errorCode == null) {
47 return new DatastoreFailureException(exception.getErrorDetail());
49 switch (errorCode) {
50 case BAD_REQUEST:
51 return new IllegalArgumentException(exception.getErrorDetail());
53 case CONCURRENT_TRANSACTION:
54 return new ConcurrentModificationException(exception.getErrorDetail());
56 case NEED_INDEX:
57 return new DatastoreNeedIndexException(exception.getErrorDetail());
59 case TIMEOUT:
60 case BIGTABLE_ERROR:
61 return new DatastoreTimeoutException(exception.getErrorDetail());
63 case COMMITTED_BUT_STILL_APPLYING:
64 return new CommittedButStillApplyingException(exception.getErrorDetail());
66 case INTERNAL_ERROR:
67 default:
68 return new DatastoreFailureException(exception.getErrorDetail());
72 abstract static class AsyncCallWrapper<S, T> extends FutureWrapper<S, T> {
73 AsyncCallWrapper(Future<S> response) {
74 super(response);
77 @Override
78 protected Throwable convertException(Throwable cause) {
79 if (cause instanceof ApiProxy.ApplicationException) {
80 return translateError((ApiProxy.ApplicationException) cause);
82 return cause;
86 static <T extends ProtocolMessage<T>> Future<T> makeAsyncCall(ApiConfig apiConfig,
87 DatastoreService_3.Method method, ProtocolMessage<?> request, final T responseProto) {
88 Future<byte[]> response = ApiProxy.makeAsyncCall(DATASTORE_V3_PACKAGE, method.name(),
89 request.toByteArray(), apiConfig);
90 return new AsyncCallWrapper<byte[], T>(response) {
91 @Override
92 protected T wrap(byte[] responseBytes) {
93 if (responseBytes != null) {
94 responseProto.parseFrom(responseBytes);
96 return responseProto;
101 static <T extends MessageLite> Future<T> makeAsyncCall(ApiProxy.ApiConfig apiConfig,
102 Datastore.Method method, MessageLite request, Parser<T> responseParser) {
103 return makeAsyncCall(apiConfig, method, request.toByteArray(), responseParser);
106 static <T extends MessageLite> Future<T> makeAsyncCall(ApiProxy.ApiConfig apiConfig,
107 Datastore.Method method, byte[] request, final Parser<T> responseParser) {
108 Future<byte[]> response = ApiProxy.makeAsyncCall(CLOUD_DATASTORE_V1_PACKAGE, method.name(),
109 request, apiConfig);
110 return new AsyncCallWrapper<byte[], T>(response) {
111 @Override
112 protected T wrap(byte[] responseBytes) throws Exception {
113 if (responseBytes != null) {
114 return responseParser.parseFrom(responseBytes);
116 return responseParser.parsePartialFrom(new byte[0]);
121 static String getCurrentProjectId() {
122 return toProjectId(getCurrentAppId());
125 static String toProjectId(String appId) {
126 return appIdentityService.parseFullAppId(appId).getId();
129 static String getCurrentAppId() {
130 ApiProxy.Environment environment = ApiProxy.getCurrentEnvironment();
131 if (environment == null) {
132 throw new NullPointerException("No API environment is registered for this thread.");
135 Object appIdOverride = environment.getAttributes().get(APP_ID_OVERRIDE_KEY);
136 if (appIdOverride != null) {
137 return (String) appIdOverride;
140 return environment.getAppId();
144 * Returns a new {@link AppIdNamespace} with the current appId and the namespace
145 * registered with the {@link NamespaceManager}
147 static AppIdNamespace getCurrentAppIdNamespace() {
148 return getCurrentAppIdNamespace(getCurrentAppId());
152 * Returns a new {@link AppIdNamespace} with the namespace currently
153 * registered with the {@link NamespaceManager} for a given appid.
155 static AppIdNamespace getCurrentAppIdNamespace(String appId) {
156 String namespace = NamespaceManager.get();
157 namespace = namespace == null ? "" : namespace;
158 return new AppIdNamespace(appId, namespace);