Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / labs / datastore / overlay / OverlayDatastoreServiceImpl.java
blobd6079f1c5f0eb6fbcb30a70ffdcc96c59126275f
1 package com.google.appengine.api.labs.datastore.overlay;
3 import static com.google.common.base.Preconditions.checkNotNull;
5 import com.google.appengine.api.datastore.BaseDatastoreService;
6 import com.google.appengine.api.datastore.DatastoreAttributes;
7 import com.google.appengine.api.datastore.DatastoreService;
8 import com.google.appengine.api.datastore.DatastoreService.KeyRangeState;
9 import com.google.appengine.api.datastore.Entity;
10 import com.google.appengine.api.datastore.EntityNotFoundException;
11 import com.google.appengine.api.datastore.Index;
12 import com.google.appengine.api.datastore.Key;
13 import com.google.appengine.api.datastore.KeyRange;
14 import com.google.appengine.api.datastore.Transaction;
15 import com.google.appengine.api.datastore.TransactionOptions;
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.Maps;
18 import com.google.common.collect.Sets;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
25 /**
26 * An implementation of {@link DatastoreService} using an overlay model. Conceptually, an overlay
27 * Datastore is based on some other Datastore (the "parent"). The overlay allows developers to
28 * effectively update or delete entities on the parent, but without actually modifying the data that
29 * the parent stores. (There is one exception: ID allocation is forwarded to the parent Datastore.)
31 final class OverlayDatastoreServiceImpl extends OverlayBaseDatastoreServiceImpl
32 implements DatastoreService {
33 private final DatastoreService datastore;
34 private final DatastoreService parent;
36 OverlayDatastoreServiceImpl(DatastoreService datastore, DatastoreService parent) {
37 this.datastore = checkNotNull(datastore);
38 this.parent = checkNotNull(parent);
41 @Override
42 public Entity get(Key key) throws EntityNotFoundException {
43 checkNotNull(key);
44 return getImpl(datastore, key);
47 @Override
48 public Entity get( Transaction txn, Key key) throws EntityNotFoundException {
49 checkNotNull(key);
50 return getImpl(getTxnDatastore(txn), key);
53 private Entity getImpl(DatastoreService datastore, Key key) throws EntityNotFoundException {
54 checkNotNull(datastore);
55 checkNotNull(key);
56 Entity result = getImpl(datastore, ImmutableList.of(key)).get(key);
57 if (result == null) {
58 throw new EntityNotFoundException(key);
60 return result;
63 @Override
64 public Map<Key, Entity> get(Iterable<Key> keys) {
65 checkNotNull(keys);
66 return getImpl(datastore, keys);
69 @Override
70 public Map<Key, Entity> get( Transaction txn, Iterable<Key> keys) {
71 checkNotNull(keys);
72 return getImpl(getTxnDatastore(txn), keys);
75 private Map<Key, Entity> getImpl(DatastoreService datastore, Iterable<Key> keys) {
76 checkNotNull(datastore);
77 checkNotNull(keys);
79 Map<Key, Entity> results = datastore.get(OverlayUtils.getKeysAndTombstoneKeys(keys));
81 Set<Key> remainingKeys = Sets.newHashSet(keys);
82 Iterator<Map.Entry<Key, Entity>> entryIterator = results.entrySet().iterator();
83 while (entryIterator.hasNext()) {
84 Map.Entry<Key, Entity> entry = entryIterator.next();
85 if (OverlayUtils.isTombstone(entry.getValue())) {
86 entryIterator.remove();
87 remainingKeys.remove(OverlayUtils.getKeyFromTombstoneKey(entry.getKey()));
88 } else {
89 remainingKeys.remove(entry.getKey());
93 results.putAll(parent.get(null, remainingKeys));
95 return results;
98 @Override
99 public Key put(Entity entity) {
100 checkNotNull(entity);
101 return put(ImmutableList.of(entity)).get(0);
104 @Override
105 public Key put( Transaction txn, Entity entity) {
106 checkNotNull(entity);
107 return put(txn, ImmutableList.of(entity)).get(0);
110 @Override
111 public List<Key> put(Iterable<Entity> entities) {
112 checkNotNull(entities);
113 return putImpl(datastore, entities);
116 @Override
117 public List<Key> put( Transaction txn, Iterable<Entity> entities) {
118 checkNotNull(entities);
119 return putImpl(getTxnDatastore(txn), entities);
122 private List<Key> putImpl(DatastoreService datastore, Iterable<Entity> entities) {
123 checkNotNull(datastore);
124 checkNotNull(entities);
126 Map<IncompleteKey, Integer> idsNeededMap = OverlayUtils.getIdsNeededMap(entities);
128 Map<IncompleteKey, Iterator<Key>> idsAllocatedMap = Maps.newHashMap();
129 for (Map.Entry<IncompleteKey, Integer> entry : idsNeededMap.entrySet()) {
130 IncompleteKey incompleteKey = entry.getKey();
131 idsAllocatedMap.put(incompleteKey, incompleteKey.parent == null
132 ? allocateIds(incompleteKey.kind, entry.getValue()).iterator()
133 : allocateIds(incompleteKey.parent, incompleteKey.kind, entry.getValue()).iterator());
136 List<Entity> completedEntities = OverlayUtils.completeEntityKeys(entities, idsAllocatedMap);
138 List<Key> keys = datastore.put(completedEntities);
140 datastore.delete(OverlayUtils.getTombstoneKeys(keys));
142 return keys;
145 @Override
146 public void delete(Key... keys) {
147 checkNotNull(keys);
148 delete(ImmutableList.copyOf(keys));
151 @Override
152 public void delete( Transaction txn, Key... keys) {
153 checkNotNull(keys);
154 delete(txn, ImmutableList.copyOf(keys));
157 @Override
158 public void delete(Iterable<Key> keys) {
159 checkNotNull(keys);
160 deleteImpl(datastore, keys);
163 @Override
164 public void delete( Transaction txn, Iterable<Key> keys) {
165 checkNotNull(keys);
166 deleteImpl(getTxnDatastore(txn), keys);
169 private void deleteImpl(DatastoreService datastore, Iterable<Key> keys) {
170 checkNotNull(datastore);
171 checkNotNull(keys);
173 datastore.put(OverlayUtils.getTombstonesForKeys(keys));
175 datastore.delete(keys);
178 @Override
179 public Transaction beginTransaction() {
180 return datastore.beginTransaction();
183 @Override
184 public Transaction beginTransaction(TransactionOptions options) {
185 checkNotNull(options);
186 return datastore.beginTransaction(options);
189 @Override
190 public KeyRange allocateIds(String kind, long num) {
191 checkNotNull(kind);
192 return parent.allocateIds(kind, num);
195 @Override
196 public KeyRange allocateIds(Key parent, String kind, long num) {
197 checkNotNull(parent);
198 checkNotNull(kind);
199 return this.parent.allocateIds(parent, kind, num);
202 @Override
203 public KeyRangeState allocateIdRange(KeyRange range) {
204 checkNotNull(range);
205 return this.parent.allocateIdRange(range);
208 @Override
209 public DatastoreAttributes getDatastoreAttributes() {
210 return datastore.getDatastoreAttributes();
213 @Override
214 public Map<Index, Index.IndexState> getIndexes() {
215 return datastore.getIndexes();
218 @Override
219 public Map<Key, Entity> getFromOverlayOnly( Transaction txn, Iterable<Key> keys) {
220 checkNotNull(keys);
221 return datastore.get(txn, keys);
224 @Override
225 protected BaseDatastoreService getParentBaseDatastoreService() {
226 return parent;
229 @Override
230 protected BaseDatastoreService getUnderlyingBaseDatastoreService() {
231 return datastore;
235 * Gets a version of the Datastore that is linked to {@code txn}.
237 private DatastoreService getTxnDatastore( Transaction txn) {
238 return new TransactionLinkedDatastoreServiceImpl(datastore, txn);