Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / BaseDatastoreServiceImpl.java
blob26d0fdec3a9ab31d1095e7ca7b616379591cf843
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.appengine.api.datastore;
5 import static com.google.common.base.Preconditions.checkArgument;
7 import com.google.apphosting.api.ApiProxy;
8 import com.google.apphosting.api.DatastorePb;
10 import java.util.concurrent.Future;
11 import java.util.logging.Logger;
13 /**
14 * State and behavior that is common to both synchronous and asynchronous
15 * Datastore API implementations.
18 abstract class BaseDatastoreServiceImpl {
19 /**
20 * It doesn't actually matter what this value is, the back end will set its
21 * own deadline. All that matters is that we set a value.
23 static final long ARBITRARY_FAILOVER_READ_MS = -1;
25 /**
26 * User-provided config options.
28 private final DatastoreServiceConfig datastoreServiceConfig;
30 /**
31 * Config that we'll pass to all api calls.
33 final ApiProxy.ApiConfig apiConfig;
35 /**
36 * Knows which transaction to use when the user does not explicitly provide
37 * one.
39 final TransactionStack defaultTxnProvider;
41 final Logger logger = Logger.getLogger(getClass().getName());
43 BaseDatastoreServiceImpl(DatastoreServiceConfig datastoreServiceConfig,
44 TransactionStack defaultTxnProvider) {
45 this.datastoreServiceConfig = datastoreServiceConfig;
46 this.apiConfig = createApiConfig(datastoreServiceConfig);
47 this.defaultTxnProvider = defaultTxnProvider;
50 protected DatastoreServiceConfig getDatastoreServiceConfig() {
51 return datastoreServiceConfig;
54 private ApiProxy.ApiConfig createApiConfig(DatastoreServiceConfig config) {
55 ApiProxy.ApiConfig apiConfig = new ApiProxy.ApiConfig();
56 apiConfig.setDeadlineInSeconds(config.getDeadline());
57 return apiConfig;
60 /**
61 * Helper class used to encapsulate the result of a call to
62 * {@link #getOrCreateTransaction()}.
64 static final class GetOrCreateTransactionResult {
66 private final boolean isNew;
67 private final Transaction txn;
69 GetOrCreateTransactionResult(boolean isNew,Transaction txn) {
70 this.isNew = isNew;
71 this.txn = txn;
74 /**
75 * @return {@code true} if the Transaction was created and should therefore
76 * be closed before the end of the operation, {@code false} otherwise.
78 public boolean isNew() {
79 return isNew;
82 /**
83 * @return The Transaction to use. Can be {@code null}.
85 public Transaction getTransaction() {
86 return txn;
90 static void validateQuery(Query query) {
91 checkArgument(query.getFilterPredicates().isEmpty() || query.getFilter() == null,
92 "A query cannot have both a filter and filter predicates set.");
93 checkArgument(query.getProjections().isEmpty() || !query.isKeysOnly(),
94 "A query cannot have both projections and keys-only set.");
97 /**
98 * Return the current transaction if one already exists, otherwise create
99 * a new transaction or throw an exception according to the
100 * {@link ImplicitTransactionManagementPolicy}.
102 GetOrCreateTransactionResult getOrCreateTransaction() {
103 Transaction currentTxn = getCurrentTransaction(null);
104 if (currentTxn != null) {
105 return new GetOrCreateTransactionResult(false, currentTxn);
108 switch(datastoreServiceConfig.getImplicitTransactionManagementPolicy()) {
109 case NONE:
110 return new GetOrCreateTransactionResult(false, null);
111 case AUTO:
112 return new GetOrCreateTransactionResult(true, beginTransactionInternal(
113 TransactionOptions.Builder.withDefaults()));
114 default:
115 final String msg = "Unexpected Transaction Creation Policy: " +
116 datastoreServiceConfig.getImplicitTransactionManagementPolicy();
117 logger.severe(msg);
118 throw new IllegalArgumentException(msg);
122 static DatastorePb.Transaction localTxnToRemoteTxn(Transaction local) {
123 DatastorePb.Transaction remote = new DatastorePb.Transaction();
124 remote.setApp(local.getApp());
125 remote.setHandle(Long.parseLong(local.getId()));
126 return remote;
129 Transaction beginTransactionInternal(TransactionOptions options) {
130 DatastorePb.Transaction remoteTxn = new DatastorePb.Transaction();
131 DatastorePb.BeginTransactionRequest request = new DatastorePb.BeginTransactionRequest();
132 request.setApp(DatastoreApiHelper.getCurrentAppId());
133 request.setAllowMultipleEg(options.isXG());
135 Future<DatastorePb.Transaction> future =
136 DatastoreApiHelper.makeAsyncCall(apiConfig, "BeginTransaction", request, remoteTxn);
138 Transaction localTxn = new TransactionImpl(apiConfig, request.getApp(), future,
139 defaultTxnProvider, datastoreServiceConfig.getDatastoreCallbacks());
141 defaultTxnProvider.push(localTxn);
142 return localTxn;
145 public Transaction getCurrentTransaction() {
146 return defaultTxnProvider.peek();
149 public Transaction getCurrentTransaction(Transaction returnedIfNoTxn) {
150 return defaultTxnProvider.peek(returnedIfNoTxn);