1 package com
.google
.appengine
.api
.labs
.datastore
.overlay
;
3 import static com
.google
.common
.base
.Preconditions
.checkArgument
;
4 import static com
.google
.common
.base
.Preconditions
.checkNotNull
;
5 import static com
.google
.common
.base
.Preconditions
.checkState
;
7 import com
.google
.appengine
.api
.datastore
.Entity
;
8 import com
.google
.appengine
.api
.datastore
.Key
;
9 import com
.google
.appengine
.api
.datastore
.KeyFactory
;
10 import com
.google
.common
.collect
.ImmutableList
;
11 import com
.google
.common
.collect
.Maps
;
13 import java
.util
.Iterator
;
14 import java
.util
.List
;
16 import java
.util
.Objects
;
19 * A collection of utility methods and constants for overlay Datastores.
21 final class OverlayUtils
{
23 private static final String TOMBSTONE_UUID
= "EB4BD565-1C12-494B-9A6D-182BA54D0B3F";
26 * Do not instantiate this class.
28 private OverlayUtils() {}
31 * Determines whether an entity is a tombstone.
33 static boolean isTombstone(Entity entity
) {
34 return TOMBSTONE_UUID
.equals(entity
.getKind());
38 * Given a {@code tombstoneKey}, returns the key where the associated real entity would be stored,
41 static Key
getKeyFromTombstoneKey(Key tombstoneKey
) {
42 checkNotNull(tombstoneKey
);
43 return tombstoneKey
.getParent();
47 * Creates a tombstone entity corresponding to {@code key}.
50 * @return a tombstone entity for that key
52 static Entity
getTombstoneForKey(Key key
) {
54 return new Entity(getTombstoneKey(key
));
58 * Returns the tombstone key corresponding to {@code key}.
60 static Key
getTombstoneKey(Key key
) {
62 return key
.getChild(TOMBSTONE_UUID
, TOMBSTONE_UUID
);
66 * Returns the tombstone keys corresponding to {@code keys}.
68 static List
<Key
> getTombstoneKeys(Iterable
<Key
> keys
) {
70 ImmutableList
.Builder
<Key
> newKeys
= ImmutableList
.<Key
>builder();
71 for (Key key
: keys
) {
72 newKeys
.add(getTombstoneKey(key
));
74 return newKeys
.build();
78 * Returns a list containing both the elements of {@code keys}, and the tombstone keys
79 * corresponding to the elements of {@code keys}.
81 static List
<Key
> getKeysAndTombstoneKeys(Iterable
<Key
> keys
) {
83 ImmutableList
.Builder
<Key
> newKeys
= ImmutableList
.<Key
>builder();
84 for (Key key
: keys
) {
86 newKeys
.add(getTombstoneKey(key
));
88 return newKeys
.build();
92 * Returns a list containing the tombstone keys corresponding to the keys of {@code entities}.
94 static List
<Key
> getTombstoneKeysForEntities(Iterable
<Entity
> entities
) {
95 checkNotNull(entities
);
96 ImmutableList
.Builder
<Key
> newKeys
= ImmutableList
.<Key
>builder();
97 for (Entity entity
: entities
) {
98 Key key
= entity
.getKey();
99 newKeys
.add(getTombstoneKey(key
));
101 return newKeys
.build();
105 * Returns a list containing both the keys of the elements of {@code entities}, and the tombstone
106 * keys corresponding to those keys.
108 static List
<Key
> getKeysAndTombstoneKeysForEntities(Iterable
<Entity
> entities
) {
109 checkNotNull(entities
);
110 ImmutableList
.Builder
<Key
> newKeys
= ImmutableList
.<Key
>builder();
111 for (Entity entity
: entities
) {
112 Key key
= entity
.getKey();
114 newKeys
.add(getTombstoneKey(key
));
116 return newKeys
.build();
120 * Creates a list of tombstone entities corresponding to {@code keys}.
122 static List
<Entity
> getTombstonesForKeys(Iterable
<Key
> keys
) {
124 ImmutableList
.Builder
<Entity
> tombstones
= ImmutableList
.<Entity
>builder();
125 for (Key key
: keys
) {
126 tombstones
.add(getTombstoneForKey(key
));
128 return tombstones
.build();
132 * Returns an entity that is the same as {code @entity}, but where the key is replaced by
133 * {@code newKey}. This method should only be called if {@code entity} has an incomplete key, and
134 * if {@code newKey} has the same kind and parent as {@code entity}.
136 static Entity
completeKey(Entity entity
, Key newKey
) {
137 checkNotNull(entity
);
138 checkNotNull(newKey
);
139 checkArgument(!entity
.getKey().isComplete());
140 checkArgument(Objects
.equals(entity
.getParent(), newKey
.getParent()));
141 checkArgument(Objects
.equals(entity
.getKind(), newKey
.getKind()));
142 Entity newEntity
= new Entity(newKey
);
143 newEntity
.setPropertiesFrom(entity
);
148 * Returns a map that indicates how many IDs need to be allocated for each parent-kind combination
149 * represented in {@code entities}.
151 static Map
<IncompleteKey
, Integer
> getIdsNeededMap(Iterable
<Entity
> entities
) {
152 Map
<IncompleteKey
, Integer
> idsNeededMap
= Maps
.newHashMap();
153 for (Entity entity
: entities
) {
154 if (!entity
.getKey().isComplete()) {
155 IncompleteKey incompleteKey
= new IncompleteKey(entity
);
156 Integer countInteger
= idsNeededMap
.get(incompleteKey
);
157 if (countInteger
!= null) {
158 idsNeededMap
.put(incompleteKey
, countInteger
+ 1);
160 idsNeededMap
.put(incompleteKey
, 1);
168 * Returns the subset of the input entities that already have complete keys.
170 static List
<Entity
> getEntitiesWithPreexistingCompleteKeys(Iterable
<Entity
> entities
) {
171 ImmutableList
.Builder
<Entity
> entitiesWithCompleteKeys
= ImmutableList
.<Entity
>builder();
172 for (Entity entity
: entities
) {
173 if (entity
.getKey().isComplete()) {
174 entitiesWithCompleteKeys
.add(entity
);
177 return entitiesWithCompleteKeys
.build();
181 * Assigns IDs from {@code idsAllocatedMap} to incomplete keys in {@code entities}, after
182 * translating them from the default ID range into the overlay ID range.
184 static List
<Entity
> translateAndCompleteEntityKeys(Iterable
<Entity
> entities
, Map
<IncompleteKey
,
185 Iterator
<Key
>> idsAllocatedMap
) {
186 ImmutableList
.Builder
<Entity
> entitiesWithCompleteKeys
= ImmutableList
.<Entity
>builder();
187 for (Entity entity
: entities
) {
188 Entity newEntity
= entity
;
189 if (!entity
.getKey().isComplete()) {
190 IncompleteKey incompleteKey
= new IncompleteKey(entity
);
191 Iterator
<Key
> keyIterator
= idsAllocatedMap
.get(incompleteKey
);
192 Key k
= keyIterator
.next();
193 Key newKey
= KeyFactory
.createKey(k
.getParent(), k
.getKind(),
194 IdAllocationPolicy
.overlayIdFromDefaultId(k
.getId()));
195 newEntity
= OverlayUtils
.completeKey(entity
, newKey
);
197 entitiesWithCompleteKeys
.add(newEntity
);
199 for (Iterator
<Key
> iterator
: idsAllocatedMap
.values()) {
200 checkState(!iterator
.hasNext());
202 return entitiesWithCompleteKeys
.build();