1.9.22 release.
[gae.git] / java / src / main / com / google / appengine / api / datastore / KeyFactory.java
blob8d878c0d5a39e6429182ba97d20c9d32df8f5f5c
1 // Copyright 2007 Google Inc. All rights reserved.
3 package com.google.appengine.api.datastore;
5 import static com.google.common.io.BaseEncoding.base64Url;
7 import com.google.common.base.CharMatcher;
8 import com.google.storage.onestore.v3.OnestoreEntity.Reference;
10 /**
11 * This class enables direct creation of {@code Key} objects, both in
12 * the root entity group (no parent) and as the child of a given
13 * parent. Keys can also be created indirectly by putting named
14 * Entities into the datastore, which will allocate a new key. See
15 * {@link Entity#Entity(String, String)} for details.
17 * <p>This class also has methods for encoding and decoding
18 * {@code Key} objects to and from strings. Clients should not make
19 * any assumptions about the encoding format, except that it is a
20 * websafe string that does not need to be quoted when used in HTML or
21 * in URLs.
23 * @see Entity
25 public class KeyFactory {
27 /**
28 * Creates a new {@code Key} having no parent from its kind and ID.
30 * @param kind the kind of the key to create
31 * @param id the numeric identifier of the key in {@code kind}, unique
32 * across all root entities of this kind, must not be zero
34 public static Key createKey(String kind, long id) {
35 return createKey(null, kind, id);
38 /**
39 * Creates a new {@code Key} with the provided parent from its kind and ID.
41 * @param parent the parent of the key to create, can be {@code null}
42 * @param kind the kind of the key to create
43 * @param id the numeric identifier of the key in {@code kind}, unique
44 * across all entities of this kind with the same parent, must not be zero
46 public static Key createKey(Key parent, String kind, long id) {
47 return createKey(parent, kind, id, null);
50 static Key createKey(Key parent, String kind, long id, AppIdNamespace appIdNamespace) {
51 if (id == 0L) {
52 throw new IllegalArgumentException("id cannot be zero");
54 return new Key(kind, parent, id, appIdNamespace);
57 /**
58 * Creates a new {@code Key} having no parent from its kind and name.
60 * @param kind the kind of the key to create
61 * @param name the name of the key in {@code kind}, as an arbitrary string
62 * unique across all root entities of this {@code kind}
64 public static Key createKey(String kind, String name) {
65 return createKey(null, kind, name);
68 /**
69 * Creates a new {@code Key} with the provided parent from its kind and name.
71 * @param parent the parent of the key to create, can be {@code null}
72 * @param kind the kind of the key to create
73 * @param name the name of the key in {@code kind}, as an arbitrary string
74 * unique across all entities of this {@code kind} with the same parent
76 public static Key createKey(Key parent, String kind, String name) {
77 return createKey(parent, kind, name, null);
80 static Key createKey(Key parent, String kind, String name, AppIdNamespace appIdNamespace) {
81 if (name == null || name.length() == 0) {
82 throw new IllegalArgumentException("name cannot be null or empty");
84 return new Key(kind, parent, name, appIdNamespace);
87 /**
88 * Shorthand for invoking {@link #keyToString(Key)} on the result of
89 * {@link #createKey(String, long)}
91 * @param kind the kind of the key to create
92 * @param id the numeric identifier of the key in {@code kind}, unique
93 * across all root entities of this kind, must not be zero
94 * @return A websafe {@code String} representation of the {@link Key} that
95 * was created
97 public static String createKeyString(String kind, long id) {
98 return keyToString(createKey(kind, id));
102 * Shorthand for invoking {@link #keyToString(Key)} on the result of
103 * {@link #createKey(Key, String, long)}
105 * @param parent the parent of the key to create, can be {@code null}.
106 * @param kind the kind of the key to create
107 * @param id the numeric identifier of the key in {@code kind}, unique
108 * across entities of this kind with the same parent, must not be zero
109 * @return A websafe {@code String} representation of the {@link Key} that
110 * was created
112 public static String createKeyString(Key parent, String kind, long id) {
113 return keyToString(createKey(parent, kind, id));
117 * Shorthand for invoking {@link #keyToString(Key)} on the result of
118 * {@link #createKey(String, String)}
120 * @param kind the kind of the key to create
121 * @param name the name of the key in {@code kind}, as an arbitrary string
122 * unique across root entities of this {@code kind}
123 * @return A websafe {@code String} representation of the {@link Key} that
124 * was created
126 public static String createKeyString(String kind, String name) {
127 return keyToString(createKey(kind, name));
131 * Shorthand for invoking {@link #keyToString(Key)} on the result of
132 * {@link #createKey(Key, String, String)}
134 * @param parent the parent of the key to create, can be {@code null}.
135 * @param kind the kind of the key to create
136 * @param name the name of the key in {@code kind}, as an arbitrary string
137 * unique across entities of this {@code kind} with the same parent
138 * @return A websafe {@code String} representation of the {@link Key} that
139 * was created
141 public static String createKeyString(Key parent, String kind, String name) {
142 return keyToString(createKey(parent, kind, name));
146 * Converts a {@code Key} into a websafe string. For example, this string
147 * can safely be used as an URL parameter embedded in a HTML document.
148 * Note that
149 * <code>
150 * key.equals(KeyFactory.stringToKey(KeyFactory.keyToString(key))
151 * </code>
152 * should evaluate to {@code true}.
154 * @param key The {@code Key} to convert to a {@code String}.
156 * @return A websafe {@code String} representation of the provided
157 * {@code String}.
159 * @throws IllegalArgumentException If the specified {@code Key}
160 * is incomplete.
162 public static String keyToString(Key key) {
163 if (!key.isComplete()) {
164 throw new IllegalArgumentException("Key is incomplete.");
165 } else {
166 Reference reference = KeyTranslator.convertToPb(key);
167 return base64Url().omitPadding().encode(reference.toByteArray());
172 * Converts a {@code String}-representation of a {@code Key} into the
173 * {@code Key} instance it represents. Note that
174 * <code>
175 * str.equals(KeyFactory.keyToString(KeyFactory.stringToKey(str))
176 * </code>
177 * should evaluate to {@code true} for all strings returned by
178 * {@link KeyFactory#keyToString}.
180 * @param encoded The {@code String} representation of a {@code Key}.
182 * @return The {@code Key} that the given {@code String} represents.
184 * @throws IllegalArgumentException If the string cannot be parsed.
186 public static Key stringToKey(String encoded) {
187 int modulo = encoded.length() % 4;
188 if (modulo != 0) {
189 encoded += "====".substring(modulo);
192 byte[] decodedBytes;
193 try {
194 decodedBytes = base64Url().decode(
195 CharMatcher.WHITESPACE.removeFrom(encoded));
196 } catch (IllegalArgumentException ex) {
197 throw new IllegalArgumentException("Cannot parse: " + encoded, ex);
200 Reference reference = new Reference();
201 reference.parseFrom(decodedBytes);
202 return KeyTranslator.createFromPb(reference);
206 * Helper class that aids in the construction of {@link Key Keys} with
207 * ancestors. Initialize the {@code Builder} with the topmost ancestor
208 * in your key path and then add children using the {@link #addChild}
209 * overload that best suits your needs. When finished adding children,
210 * call {@link #getKey()} to retrieve your {@link Key} or
211 * {@link #getString()} to retrieve your {@link Key} encoded as a websafe
212 * {@link String}.
214 * Examples:<br>
216 * <pre>
217 * import com.google.appengine.api.datastore.KeyFactory.Builder;
219 * ...
221 * Key key = new Builder("Person", 88).addChild("Address", 24).getKey();
222 * String keyStr = new Builder("Photo Album", "Vacation").addChild("Photo", 1424).getString();
223 * </pre>
225 public static final class Builder {
226 private Key current;
229 * Create a {@code Builder}, establishing a {@link Key} constructed from
230 * the provided kind and name as the topmost ancestor.
232 * @param kind the kind of the topmost ancestor
233 * @param name the name of the topmost ancestor in {@code kind}, as an
234 * arbitrary string unique across root entities of this {@code kind}
236 public Builder(String kind, String name) {
237 current = createKey(null, kind, name);
241 * Create a {@code Builder}, establishing a {@link Key} constructed from
242 * the provided kind and id as the topmost ancestor.
244 * @param kind the kind of the topmost ancestor
245 * @param id the numeric identifier of the topmost ancestor in {@code kind},
246 * unique across root entities of this kind, must not be zero
248 public Builder(String kind, long id) {
249 current = createKey(null, kind, id);
253 * Create a {@code Builder}, establishing the provided {@link Key} as the
254 * topmost ancestor.
256 * @param key the topmost ancestor
258 public Builder(Key key) {
259 current = key;
263 * Add a {@link Key} constructed from the provided kind and name
264 * as the child of the {@link Key} most recently added to the
265 * {@code Builder}.
267 * @param kind the kind of the child
268 * @param name the name of the child in {@code kind}, as an arbitrary string
269 * unique across entities of this {@code kind} with the same parent
270 * @return {@code this}
272 public Builder addChild(String kind, String name) {
273 current = createKey(current, kind, name);
274 return this;
278 * Add a {@link Key} constructed from the provided kind and id
279 * as the child of the {@link Key} most recently added to the
280 * {@code Builder}.
282 * @param kind the kind of the child
283 * @param id the numeric identifier of the child in {@code kind},
284 * unique across entities of this kind with the same parent, must not be
285 * zero
286 * @return {@code this}
288 public Builder addChild(String kind, long id) {
289 current = createKey(current, kind, id);
290 return this;
294 * @return The most recently added {@link Key}.
296 public Key getKey() {
297 return current;
301 * @return The most recently added {@link Key}, encoded as a websafe
302 * {@link String}.
304 public String getString() {
305 return keyToString(current);
309 private KeyFactory() {