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
.utils
.FutureWrapper
;
6 import com
.google
.apphosting
.api
.ApiProxy
;
7 import com
.google
.apphosting
.api
.ApiProxy
.ApiConfig
;
8 import com
.google
.apphosting
.datastore
.DatastoreV3Pb
.DatastoreService_3
;
9 import com
.google
.apphosting
.datastore
.DatastoreV3Pb
.Error
;
10 import com
.google
.apphosting
.datastore
.DatastoreV4
.DatastoreV4Service
;
11 import com
.google
.io
.protocol
.ProtocolMessage
;
12 import com
.google
.protobuf
.MessageLite
;
13 import com
.google
.protobuf
.Parser
;
15 import java
.util
.ConcurrentModificationException
;
16 import java
.util
.concurrent
.Future
;
19 * Helper methods and constants shared by classes that implement the java api
20 * on top of the datastore.
21 * Note: user should not access this class directly.
24 public final class DatastoreApiHelper
{
26 static final String PACKAGE
= "datastore_v3";
27 static final String V4_PACKAGE
= "datastore_v4";
30 * Key to put in {@link ApiProxy.Environment#getAttributes()} to override the app id used by the
31 * datastore api. If absent, {@link ApiProxy.Environment#getAppId()} will be used.
33 @SuppressWarnings("javadoc")
34 static final String APP_ID_OVERRIDE_KEY
= "com.google.appengine.datastore.AppIdOverride";
36 private DatastoreApiHelper() {}
38 public static RuntimeException
translateError(ApiProxy
.ApplicationException exception
) {
39 Error
.ErrorCode errorCode
= Error
.ErrorCode
.valueOf(exception
.getApplicationError());
40 if (errorCode
== null) {
41 return new DatastoreFailureException(exception
.getErrorDetail());
45 return new IllegalArgumentException(exception
.getErrorDetail());
47 case CONCURRENT_TRANSACTION
:
48 return new ConcurrentModificationException(exception
.getErrorDetail());
51 return new DatastoreNeedIndexException(exception
.getErrorDetail());
55 return new DatastoreTimeoutException(exception
.getErrorDetail());
57 case COMMITTED_BUT_STILL_APPLYING
:
58 return new CommittedButStillApplyingException(exception
.getErrorDetail());
62 return new DatastoreFailureException(exception
.getErrorDetail());
66 abstract static class AsyncCallWrapper
<S
, T
> extends FutureWrapper
<S
, T
> {
67 AsyncCallWrapper(Future
<S
> response
) {
72 protected Throwable
convertException(Throwable cause
) {
73 if (cause
instanceof ApiProxy
.ApplicationException
) {
74 return translateError((ApiProxy
.ApplicationException
) cause
);
80 static <T
extends ProtocolMessage
<T
>> Future
<T
> makeAsyncCall(ApiConfig apiConfig
,
81 DatastoreService_3
.Method method
, ProtocolMessage
<?
> request
, final T responseProto
) {
82 Future
<byte[]> response
=
83 ApiProxy
.makeAsyncCall(PACKAGE
, method
.name(), request
.toByteArray(), apiConfig
);
84 return new AsyncCallWrapper
<byte[], T
>(response
) {
86 protected T
wrap(byte[] responseBytes
) {
87 if (responseBytes
!= null) {
88 responseProto
.parseFrom(responseBytes
);
95 static <T
extends MessageLite
> Future
<T
> makeAsyncCall(ApiProxy
.ApiConfig apiConfig
,
96 DatastoreV4Service
.Method method
, MessageLite request
, Parser
<T
> responseParser
) {
97 return makeAsyncCall(apiConfig
, method
, request
.toByteArray(), responseParser
);
100 static <T
extends MessageLite
> Future
<T
> makeAsyncCall(ApiProxy
.ApiConfig apiConfig
,
101 DatastoreV4Service
.Method method
, byte[] request
, final Parser
<T
> responseParser
) {
102 Future
<byte[]> response
= ApiProxy
.makeAsyncCall(V4_PACKAGE
, method
.name(), request
, apiConfig
);
103 return new AsyncCallWrapper
<byte[], T
>(response
) {
105 protected T
wrap(byte[] responseBytes
) throws Exception
{
106 if (responseBytes
!= null) {
107 return responseParser
.parseFrom(responseBytes
);
109 return responseParser
.parsePartialFrom(new byte[0]);
114 static String
getCurrentAppId() {
115 ApiProxy
.Environment environment
= ApiProxy
.getCurrentEnvironment();
116 if (environment
== null) {
117 throw new NullPointerException("No API environment is registered for this thread.");
120 Object appIdOverride
= environment
.getAttributes().get(APP_ID_OVERRIDE_KEY
);
121 if (appIdOverride
!= null) {
122 return (String
) appIdOverride
;
125 return environment
.getAppId();
129 * Returns a new {@link AppIdNamespace} with the current appId and the namespace
130 * registered with the {@link NamespaceManager}
132 static AppIdNamespace
getCurrentAppIdNamespace() {
133 return getCurrentAppIdNamespace(getCurrentAppId());
137 * Returns a new {@link AppIdNamespace} with the namespace currently
138 * registered with the {@link NamespaceManager} for a given appid.
140 static AppIdNamespace
getCurrentAppIdNamespace(String appId
) {
141 String namespace
= NamespaceManager
.get();
142 namespace
= namespace
== null ?
"" : namespace
;
143 return new AppIdNamespace(appId
, namespace
);