Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / api / datastore / KeyFactory.java
blob979eb53a72f4d267ab92fe4d0550f1c9189dccce
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.util.Base64;
8 import com.google.common.util.Base64DecoderException;
9 import com.google.storage.onestore.v3.OnestoreEntity.Reference;
11 /**
12 * This class enables direct creation of {@code Key} objects, both in
13 * the root entity group (no parent) and as the child of a given
14 * parent. Keys can also be created indirectly by putting named
15 * Entities into the datastore, which will allocate a new key. See
16 * {@link Entity#Entity(String, String)} for details.
18 * <p>This class also has methods for encoding and decoding
19 * {@code Key} objects to and from strings. Clients should not make
20 * any assumptions about the encoding format, except that it is a
21 * websafe string that does not need to be quoted when used in HTML or
22 * in URLs.
24 * @see Entity
26 public class KeyFactory {
28 /**
29 * Creates a new {@code Key} having no parent from its kind and ID.
31 * @param kind the kind of the key to create
32 * @param id the numeric identifier of the key in {@code kind}, unique
33 * across all root entities of this kind, must not be zero
35 public static Key createKey(String kind, long id) {
36 return createKey(null, kind, id);
39 /**
40 * Creates a new {@code Key} with the provided parent from its kind and ID.
42 * @param parent the parent of the key to create, can be {@code null}
43 * @param kind the kind of the key to create
44 * @param id the numeric identifier of the key in {@code kind}, unique
45 * across all entities of this kind with the same parent, must not be zero
47 public static Key createKey(Key parent, String kind, long id) {
48 return createKey(parent, kind, id, null);
51 static Key createKey(Key parent, String kind, long id, AppIdNamespace appIdNamespace) {
52 if (id == 0L) {
53 throw new IllegalArgumentException("id cannot be zero");
55 return new Key(kind, parent, id, appIdNamespace);
58 /**
59 * Creates a new {@code Key} having no parent from its kind and name.
61 * @param kind the kind of the key to create
62 * @param name the name of the key in {@code kind}, as an arbitrary string
63 * unique across all root entities of this {@code kind}
65 public static Key createKey(String kind, String name) {
66 return createKey(null, kind, name);
69 /**
70 * Creates a new {@code Key} with the provided parent from its kind and name.
72 * @param parent the parent of the key to create, can be {@code null}
73 * @param kind the kind of the key to create
74 * @param name the name of the key in {@code kind}, as an arbitrary string
75 * unique across all entities of this {@code kind} with the same parent
77 public static Key createKey(Key parent, String kind, String name) {
78 return createKey(parent, kind, name, null);
81 static Key createKey(Key parent, String kind, String name, AppIdNamespace appIdNamespace) {
82 if (name == null || name.length() == 0) {
83 throw new IllegalArgumentException("name cannot be null or empty");
85 return new Key(kind, parent, name, appIdNamespace);
88 /**
89 * Shorthand for invoking {@link #keyToString(Key)} on the result of
90 * {@link #createKey(String, long)}
92 * @param kind the kind of the key to create
93 * @param id the numeric identifier of the key in {@code kind}, unique
94 * across all root entities of this kind, must not be zero
95 * @return A websafe {@code String} representation of the {@link Key} that
96 * was created
98 public static String createKeyString(String kind, long id) {
99 return keyToString(createKey(kind, id));
103 * Shorthand for invoking {@link #keyToString(Key)} on the result of
104 * {@link #createKey(Key, String, long)}
106 * @param parent the parent of the key to create, can be {@code null}.
107 * @param kind the kind of the key to create
108 * @param id the numeric identifier of the key in {@code kind}, unique
109 * across entities of this kind with the same parent, must not be zero
110 * @return A websafe {@code String} representation of the {@link Key} that
111 * was created
113 public static String createKeyString(Key parent, String kind, long id) {
114 return keyToString(createKey(parent, kind, id));
118 * Shorthand for invoking {@link #keyToString(Key)} on the result of
119 * {@link #createKey(String, String)}
121 * @param kind the kind of the key to create
122 * @param name the name of the key in {@code kind}, as an arbitrary string
123 * unique across root entities of this {@code kind}
124 * @return A websafe {@code String} representation of the {@link Key} that
125 * was created
127 public static String createKeyString(String kind, String name) {
128 return keyToString(createKey(kind, name));
132 * Shorthand for invoking {@link #keyToString(Key)} on the result of
133 * {@link #createKey(Key, String, String)}
135 * @param parent the parent of the key to create, can be {@code null}.
136 * @param kind the kind of the key to create
137 * @param name the name of the key in {@code kind}, as an arbitrary string
138 * unique across entities of this {@code kind} with the same parent
139 * @return A websafe {@code String} representation of the {@link Key} that
140 * was created
142 public static String createKeyString(Key parent, String kind, String name) {
143 return keyToString(createKey(parent, kind, name));
147 * Converts a {@code Key} into a websafe string. For example, this string
148 * can safely be used as an URL parameter embedded in a HTML document.
149 * Note that
150 * <code>
151 * key.equals(KeyFactory.stringToKey(KeyFactory.keyToString(key))
152 * </code>
153 * should evaluate to {@code true}.
155 * @param key The {@code Key} to convert to a {@code String}.
157 * @return A websafe {@code String} representation of the provided
158 * {@code String}.
160 * @throws IllegalArgumentException If the specified {@code Key}
161 * is incomplete.
163 public static String keyToString(Key key) {
164 if (!key.isComplete()) {
165 throw new IllegalArgumentException("Key is incomplete.");
166 } else {
167 Reference reference = KeyTranslator.convertToPb(key);
168 return base64Url().omitPadding().encode(reference.toByteArray());
173 * Converts a {@code String}-representation of a {@code Key} into the
174 * {@code Key} instance it represents. Note that
175 * <code>
176 * str.equals(KeyFactory.keyToString(KeyFactory.stringToKey(str))
177 * </code>
178 * should evaluate to {@code true} for all strings returned by
179 * {@link KeyFactory#keyToString}.
181 * @param encoded The {@code String} representation of a {@code Key}.
183 * @return The {@code Key} that the given {@code String} represents.
185 * @throws IllegalArgumentException If the string cannot be parsed.
187 public static Key stringToKey(String encoded) {
188 int modulo = encoded.length() % 4;
189 if (modulo != 0) {
190 encoded += "====".substring(modulo);
193 byte[] encodedBytes = encoded.getBytes();
194 byte[] decodedBytes;
195 try {
196 decodedBytes = Base64.decodeWebSafe(encodedBytes, 0, encodedBytes.length);
197 } catch (Base64DecoderException ex) {
198 throw new IllegalArgumentException("Cannot parse: " + encoded, ex);
201 Reference reference = new Reference();
202 reference.parseFrom(decodedBytes);
203 return KeyTranslator.createFromPb(reference);
207 * Helper class that aids in the construction of {@link Key Keys} with
208 * ancestors. Initialize the {@code Builder} with the topmost ancestor
209 * in your key path and then add children using the {@link #addChild}
210 * overload that best suits your needs. When finished adding children,
211 * call {@link #getKey()} to retrieve your {@link Key} or
212 * {@link #getString()} to retrieve your {@link Key} encoded as a websafe
213 * {@link String}.
215 * Examples:<br>
217 * <pre>
218 * import com.google.appengine.api.datastore.KeyFactory.Builder;
220 * ...
222 * Key key = new Builder("Person", 88).addChild("Address", 24).getKey();
223 * String keyStr = new Builder("Photo Album", "Vacation").addChild("Photo", 1424).getString();
224 * </pre>
226 public static final class Builder {
227 private Key current;
230 * Create a {@code Builder}, establishing a {@link Key} constructed from
231 * the provided kind and name as the topmost ancestor.
233 * @param kind the kind of the topmost ancestor
234 * @param name the name of the topmost ancestor in {@code kind}, as an
235 * arbitrary string unique across root entities of this {@code kind}
237 public Builder(String kind, String name) {
238 current = createKey(null, kind, name);
242 * Create a {@code Builder}, establishing a {@link Key} constructed from
243 * the provided kind and id as the topmost ancestor.
245 * @param kind the kind of the topmost ancestor
246 * @param id the numeric identifier of the topmost ancestor in {@code kind},
247 * unique across root entities of this kind, must not be zero
249 public Builder(String kind, long id) {
250 current = createKey(null, kind, id);
254 * Create a {@code Builder}, establishing the provided {@link Key} as the
255 * topmost ancestor.
257 * @param key the topmost ancestor
259 public Builder(Key key) {
260 current = key;
264 * Add a {@link Key} constructed from the provided kind and name
265 * as the child of the {@link Key} most recently added to the
266 * {@code Builder}.
268 * @param kind the kind of the child
269 * @param name the name of the child in {@code kind}, as an arbitrary string
270 * unique across entities of this {@code kind} with the same parent
271 * @return {@code this}
273 public Builder addChild(String kind, String name) {
274 current = createKey(current, kind, name);
275 return this;
279 * Add a {@link Key} constructed from the provided kind and id
280 * as the child of the {@link Key} most recently added to the
281 * {@code Builder}.
283 * @param kind the kind of the child
284 * @param id the numeric identifier of the child in {@code kind},
285 * unique across entities of this kind with the same parent, must not be
286 * zero
287 * @return {@code this}
289 public Builder addChild(String kind, long id) {
290 current = createKey(current, kind, id);
291 return this;
295 * @return The most recently added {@link Key}.
297 public Key getKey() {
298 return current;
302 * @return The most recently added {@link Key}, encoded as a websafe
303 * {@link String}.
305 public String getString() {
306 return keyToString(current);
310 private KeyFactory() {