Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / DatastoreApiHelper.java
blob5275c872010fc13e0d9c38e6e3296b64d9c4588c
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.AppIdentityService.ParsedAppId;
7 import com.google.appengine.api.appidentity.AppIdentityServiceFactory;
8 import com.google.appengine.api.utils.FutureWrapper;
9 import com.google.apphosting.api.ApiProxy;
10 import com.google.apphosting.api.ApiProxy.ApiConfig;
11 import com.google.apphosting.datastore.DatastoreV3Pb.DatastoreService_3;
12 import com.google.apphosting.datastore.DatastoreV3Pb.Error;
13 import com.google.datastore.v1beta3.Datastore;
14 import com.google.io.protocol.ProtocolMessage;
15 import com.google.protobuf.MessageLite;
16 import com.google.protobuf.Parser;
17 import com.google.rpc.Code;
19 import java.util.ConcurrentModificationException;
20 import java.util.concurrent.Future;
22 /**
23 * Helper methods and constants shared by classes that implement the Java api
24 * on top of the datastore.
26 * <p>Note: users should not access this class directly.
29 public final class DatastoreApiHelper {
31 static final String DATASTORE_V3_PACKAGE = "datastore_v3";
32 static final String CLOUD_DATASTORE_V1_PACKAGE = "cloud_datastore_v1";
34 /**
35 * Key to put in {@link ApiProxy.Environment#getAttributes()} to override the app id used by the
36 * datastore api. If absent, {@link ApiProxy.Environment#getAppId()} will be used.
38 @SuppressWarnings("javadoc")
39 static final String APP_ID_OVERRIDE_KEY = "com.google.appengine.datastore.AppIdOverride";
41 private static final AppIdentityService appIdentityService =
42 AppIdentityServiceFactory.getAppIdentityService();
44 private DatastoreApiHelper() {}
46 public static RuntimeException translateError(ApiProxy.ApplicationException exception) {
47 Error.ErrorCode errorCode = Error.ErrorCode.valueOf(exception.getApplicationError());
48 if (errorCode == null) {
49 return new DatastoreFailureException(exception.getErrorDetail());
51 switch (errorCode) {
52 case BAD_REQUEST:
53 return new IllegalArgumentException(exception.getErrorDetail());
55 case CONCURRENT_TRANSACTION:
56 return new ConcurrentModificationException(exception.getErrorDetail());
58 case NEED_INDEX:
59 return new DatastoreNeedIndexException(exception.getErrorDetail());
61 case TIMEOUT:
62 case BIGTABLE_ERROR:
63 return new DatastoreTimeoutException(exception.getErrorDetail());
65 case COMMITTED_BUT_STILL_APPLYING:
66 return new CommittedButStillApplyingException(exception.getErrorDetail());
68 case INTERNAL_ERROR:
69 default:
70 return new DatastoreFailureException(exception.getErrorDetail());
74 static RuntimeException createException(Code code, String message) {
75 if (code == null) {
76 return new DatastoreFailureException(message);
78 switch (code) {
79 case INVALID_ARGUMENT:
80 return new IllegalArgumentException(message);
81 case ABORTED:
82 return new ConcurrentModificationException(message);
83 case FAILED_PRECONDITION:
84 return new DatastoreNeedIndexException(message);
85 case DEADLINE_EXCEEDED:
86 return new DatastoreTimeoutException(message);
87 case PERMISSION_DENIED:
88 case UNAVAILABLE:
89 case RESOURCE_EXHAUSTED:
90 return new IllegalStateException(message);
91 case INTERNAL:
92 default:
93 return new DatastoreFailureException(message);
97 private static RuntimeException translateCanonicalCodeError(
98 ApiProxy.ApplicationException exception) {
99 return createException(Code.valueOf(exception.getApplicationError()),
100 exception.getErrorDetail());
103 static <T extends ProtocolMessage<T>> Future<T> makeAsyncCall(ApiConfig apiConfig,
104 DatastoreService_3.Method method, ProtocolMessage<?> request, final T responseProto) {
105 Future<byte[]> response = ApiProxy.makeAsyncCall(DATASTORE_V3_PACKAGE, method.name(),
106 request.toByteArray(), apiConfig);
107 return new FutureWrapper<byte[], T>(response) {
108 @Override
109 protected T wrap(byte[] responseBytes) {
110 if (responseBytes != null) {
111 responseProto.parseFrom(responseBytes);
113 return responseProto;
116 @Override
117 protected Throwable convertException(Throwable cause) {
118 if (cause instanceof ApiProxy.ApplicationException) {
119 return translateError((ApiProxy.ApplicationException) cause);
121 return cause;
126 static <T extends MessageLite> Future<T> makeAsyncCall(ApiProxy.ApiConfig apiConfig,
127 Datastore.Method method, MessageLite request, Parser<T> responseParser) {
128 return makeAsyncCall(apiConfig, method, request.toByteArray(), responseParser);
131 static <T extends MessageLite> Future<T> makeAsyncCall(ApiProxy.ApiConfig apiConfig,
132 Datastore.Method method, byte[] request, final Parser<T> responseParser) {
133 Future<byte[]> response = ApiProxy.makeAsyncCall(CLOUD_DATASTORE_V1_PACKAGE, method.name(),
134 request, apiConfig);
135 return new FutureWrapper<byte[], T>(response) {
136 @Override
137 protected T wrap(byte[] responseBytes) throws Exception {
138 if (responseBytes != null) {
139 return responseParser.parseFrom(responseBytes);
141 return responseParser.parsePartialFrom(new byte[0]);
144 @Override
145 protected Throwable convertException(Throwable cause) {
146 if (cause instanceof ApiProxy.ApplicationException) {
147 return translateCanonicalCodeError((ApiProxy.ApplicationException) cause);
149 return cause;
154 static String getCurrentProjectId() {
155 return toProjectId(getCurrentAppId());
158 static String toProjectId(String appId) {
159 ParsedAppId parsedAppId = appIdentityService.parseFullAppId(appId);
160 if (parsedAppId.getDomain().isEmpty()) {
161 return parsedAppId.getId();
162 } else {
163 return String.format("%s:%s", parsedAppId.getDomain(), parsedAppId.getId());
167 static String getCurrentAppId() {
168 ApiProxy.Environment environment = ApiProxy.getCurrentEnvironment();
169 if (environment == null) {
170 throw new NullPointerException("No API environment is registered for this thread.");
173 Object appIdOverride = environment.getAttributes().get(APP_ID_OVERRIDE_KEY);
174 if (appIdOverride != null) {
175 return (String) appIdOverride;
178 return environment.getAppId();
182 * Returns a new {@link AppIdNamespace} with the current appId and the namespace
183 * registered with the {@link NamespaceManager}
185 static AppIdNamespace getCurrentAppIdNamespace() {
186 return getCurrentAppIdNamespace(getCurrentAppId());
190 * Returns a new {@link AppIdNamespace} with the namespace currently
191 * registered with the {@link NamespaceManager} for a given appid.
193 static AppIdNamespace getCurrentAppIdNamespace(String appId) {
194 String namespace = NamespaceManager.get();
195 namespace = namespace == null ? "" : namespace;
196 return new AppIdNamespace(appId, namespace);