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
;
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";
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());
51 return new IllegalArgumentException(exception
.getErrorDetail());
53 case CONCURRENT_TRANSACTION
:
54 return new ConcurrentModificationException(exception
.getErrorDetail());
57 return new DatastoreNeedIndexException(exception
.getErrorDetail());
61 return new DatastoreTimeoutException(exception
.getErrorDetail());
63 case COMMITTED_BUT_STILL_APPLYING
:
64 return new CommittedButStillApplyingException(exception
.getErrorDetail());
68 return new DatastoreFailureException(exception
.getErrorDetail());
72 abstract static class AsyncCallWrapper
<S
, T
> extends FutureWrapper
<S
, T
> {
73 AsyncCallWrapper(Future
<S
> response
) {
78 protected Throwable
convertException(Throwable cause
) {
79 if (cause
instanceof ApiProxy
.ApplicationException
) {
80 return translateError((ApiProxy
.ApplicationException
) 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
) {
92 protected T
wrap(byte[] responseBytes
) {
93 if (responseBytes
!= null) {
94 responseProto
.parseFrom(responseBytes
);
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(),
110 return new AsyncCallWrapper
<byte[], T
>(response
) {
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
);