All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.appengine.api.datastore.KeyFactory Maven / Gradle / Ivy

Go to download

API for Google App Engine standard environment with some of the dependencies shaded (repackaged)

There is a newer version: 2.0.27
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.appengine.api.datastore;

import static com.google.common.io.BaseEncoding.base64Url;

import com.google.common.base.CharMatcher;
import com.google.storage.onestore.v3.OnestoreEntity.Reference;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * This class enables direct creation of {@code Key} objects, both in the root entity group (no
 * parent) and as the child of a given parent. Keys can also be created indirectly by putting named
 * Entities into the datastore, which will allocate a new key. See {@link Entity#Entity(String,
 * String)} for details.
 *
 * 

This class also has methods for encoding and decoding {@code Key} objects to and from strings. * Clients should not make any assumptions about the encoding format, except that it is a websafe * string that does not need to be quoted when used in HTML or in URLs. * * @see Entity */ public class KeyFactory { /** * Creates a new {@code Key} having no parent from its kind and ID. * * @param kind the kind of the key to create * @param id the numeric identifier of the key in {@code kind}, unique across all root entities of * this kind, must not be zero */ public static Key createKey(String kind, long id) { return createKey(null, kind, id); } /** * Creates a new {@code Key} with the provided parent from its kind and ID. * * @param parent the parent of the key to create, can be {@code null} * @param kind the kind of the key to create * @param id the numeric identifier of the key in {@code kind}, unique across all entities of this * kind with the same parent, must not be zero */ public static Key createKey(@Nullable Key parent, String kind, long id) { return createKey(parent, kind, id, null); } static Key createKey( @Nullable Key parent, String kind, long id, @Nullable AppIdNamespace appIdNamespace) { if (id == 0L) { throw new IllegalArgumentException("id cannot be zero"); } return new Key(kind, parent, id, appIdNamespace); } /** * Creates a new {@code Key} having no parent from its kind and name. * * @param kind the kind of the key to create * @param name the name of the key in {@code kind}, as an arbitrary string unique across all root * entities of this {@code kind} */ public static Key createKey(String kind, String name) { return createKey(null, kind, name); } /** * Creates a new {@code Key} with the provided parent from its kind and name. * * @param parent the parent of the key to create, can be {@code null} * @param kind the kind of the key to create * @param name the name of the key in {@code kind}, as an arbitrary string unique across all * entities of this {@code kind} with the same parent */ public static Key createKey(@Nullable Key parent, String kind, String name) { return createKey(parent, kind, name, null); } static Key createKey( @Nullable Key parent, String kind, String name, @Nullable AppIdNamespace appIdNamespace) { if (name == null || name.length() == 0) { throw new IllegalArgumentException("name cannot be null or empty"); } return new Key(kind, parent, name, appIdNamespace); } /** * Shorthand for invoking {@link #keyToString(Key)} on the result of {@link #createKey(String, * long)} * * @param kind the kind of the key to create * @param id the numeric identifier of the key in {@code kind}, unique across all root entities of * this kind, must not be zero * @return A websafe {@code String} representation of the {@link Key} that was created */ public static String createKeyString(String kind, long id) { return keyToString(createKey(kind, id)); } /** * Shorthand for invoking {@link #keyToString(Key)} on the result of {@link #createKey(Key, * String, long)} * * @param parent the parent of the key to create, can be {@code null}. * @param kind the kind of the key to create * @param id the numeric identifier of the key in {@code kind}, unique across entities of this * kind with the same parent, must not be zero * @return A websafe {@code String} representation of the {@link Key} that was created */ public static String createKeyString(@Nullable Key parent, String kind, long id) { return keyToString(createKey(parent, kind, id)); } /** * Shorthand for invoking {@link #keyToString(Key)} on the result of {@link #createKey(String, * String)} * * @param kind the kind of the key to create * @param name the name of the key in {@code kind}, as an arbitrary string unique across root * entities of this {@code kind} * @return A websafe {@code String} representation of the {@link Key} that was created */ public static String createKeyString(String kind, String name) { return keyToString(createKey(kind, name)); } /** * Shorthand for invoking {@link #keyToString(Key)} on the result of {@link #createKey(Key, * String, String)} * * @param parent the parent of the key to create, can be {@code null}. * @param kind the kind of the key to create * @param name the name of the key in {@code kind}, as an arbitrary string unique across entities * of this {@code kind} with the same parent * @return A websafe {@code String} representation of the {@link Key} that was created */ public static String createKeyString(@Nullable Key parent, String kind, String name) { return keyToString(createKey(parent, kind, name)); } /** * Converts a {@code Key} into a websafe string. For example, this string can safely be used as an * URL parameter embedded in a HTML document. Note that * key.equals(KeyFactory.stringToKey(KeyFactory.keyToString(key)) * should evaluate to {@code true}. * * @param key The {@code Key} to convert to a {@code String}. * @return A websafe {@code String} representation of the provided {@code String}. * @throws IllegalArgumentException If the specified {@code Key} is incomplete. */ public static String keyToString(Key key) { // Note: This must be consistent across languages. If it changes, // make sure that the similar logic in Python changes as well. // There are also unit tests which need to be changed. if (!key.isComplete()) { throw new IllegalArgumentException("Key is incomplete."); } else { Reference reference = KeyTranslator.convertToPb(key); return base64Url().omitPadding().encode(reference.toByteArray()); } } /** * Converts a {@code String}-representation of a {@code Key} into the {@code Key} instance it * represents. Note that * str.equals(KeyFactory.keyToString(KeyFactory.stringToKey(str)) * should evaluate to {@code true} for all strings returned by {@link * KeyFactory#keyToString}. * * @param encoded The {@code String} representation of a {@code Key}. * @return The {@code Key} that the given {@code String} represents. * @throws IllegalArgumentException If the string cannot be parsed. */ public static Key stringToKey(String encoded) { // Note: This must be consistent across languages. If it changes, // make sure that the similar logic in Python changes as well. // There are unit tests which also need to be changed. int modulo = encoded.length() % 4; if (modulo != 0) { // Pad the string to a 4-byte boundary. encoded += "====".substring(modulo); } byte[] decodedBytes; try { decodedBytes = base64Url().decode(CharMatcher.whitespace().removeFrom(encoded)); } catch (IllegalArgumentException ex) { throw new IllegalArgumentException("Cannot parse: " + encoded, ex); } Reference reference = new Reference(); boolean parsed = reference.parseFrom(decodedBytes); if (!parsed) { throw new IllegalArgumentException("Could not parse Reference"); } // The validation in createFromPb should cover missing required fields, so no need for // an isInitialized check. return KeyTranslator.createFromPb(reference); } /** * Helper class that aids in the construction of {@link Key Keys} with ancestors. Initialize the * {@code Builder} with the topmost ancestor in your key path and then add children using the * {@link #addChild} overload that best suits your needs. When finished adding children, call * {@link #getKey()} to retrieve your {@link Key} or {@link #getString()} to retrieve your {@link * Key} encoded as a websafe {@link String}. * *

Examples:
* *

   * import com.google.appengine.api.datastore.KeyFactory.Builder;
   *
   * ...
   *
   * Key key = new Builder("Person", 88).addChild("Address", 24).getKey();
   * String keyStr = new Builder("Photo Album", "Vacation").addChild("Photo", 1424).getString();
   * 
*/ public static final class Builder { private Key current; /** * Create a {@code Builder}, establishing a {@link Key} constructed from the provided kind and * name as the topmost ancestor. * * @param kind the kind of the topmost ancestor * @param name the name of the topmost ancestor in {@code kind}, as an arbitrary string unique * across root entities of this {@code kind} */ public Builder(String kind, String name) { current = createKey(null, kind, name); } /** * Create a {@code Builder}, establishing a {@link Key} constructed from the provided kind and * id as the topmost ancestor. * * @param kind the kind of the topmost ancestor * @param id the numeric identifier of the topmost ancestor in {@code kind}, unique across root * entities of this kind, must not be zero */ public Builder(String kind, long id) { current = createKey(null, kind, id); } /** * Create a {@code Builder}, establishing the provided {@link Key} as the topmost ancestor. * * @param key the topmost ancestor */ public Builder(Key key) { current = key; } /** * Add a {@link Key} constructed from the provided kind and name as the child of the {@link Key} * most recently added to the {@code Builder}. * * @param kind the kind of the child * @param name the name of the child in {@code kind}, as an arbitrary string unique across * entities of this {@code kind} with the same parent * @return {@code this} */ public Builder addChild(String kind, String name) { current = createKey(current, kind, name); return this; } /** * Add a {@link Key} constructed from the provided kind and id as the child of the {@link Key} * most recently added to the {@code Builder}. * * @param kind the kind of the child * @param id the numeric identifier of the child in {@code kind}, unique across entities of this * kind with the same parent, must not be zero * @return {@code this} */ public Builder addChild(String kind, long id) { current = createKey(current, kind, id); return this; } /** Returns the most recently added {@link Key}. */ public Key getKey() { return current; } /** Returns the most recently added {@link Key}, encoded as a websafe {@link String}. */ public String getString() { return keyToString(current); } } // All methods are static. Do not instantiate. private KeyFactory() {} }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy