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

com.google.appengine.api.NamespaceManager Maven / Gradle / Ivy

There is a newer version: 2.0.31
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;

import com.google.apphosting.api.ApiProxy;
import java.util.regex.Pattern;

/**
 * Provides functions for manipulating the current namespace used for
 * App Engine APIs.
 *
 * 

The "current namespace" is the string that is returned by * {@link #get()} and used by a number of APIs including Datatore, * Memcache and Task Queue. * *

When a namespace aware class (e.g., * {@link com.google.appengine.api.datastore.Key}, * {@link com.google.appengine.api.datastore.Query} and * {@link com.google.appengine.api.memcache.MemcacheService}) is constructed, it * determines which namespace will be used by calling * {@link NamespaceManager#get()} if it is otherwise unspecified. If * {@link NamespaceManager#get()} returns null, the current namespace is unset * and these APIs will use the empty ("") namespace in its place. * *

Example:

 * {@link NamespaceManager}.{@link #set}("a-namespace");
 * MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
 * // Store record in namespace "a-namespace"
 * memcache.put("key1", "value1");
 *
 * {@link NamespaceManager}.{@link #set}("other-namespace");
 * // Store record in namespace "other-namespace"
 * memcache.put("key2", "value2");
 *
 * MemcacheService boundMemcache =
 *     MemcacheServiceFactory.getMemcacheService("specific-namespace");
 * {@link NamespaceManager}.{@link #set}("whatever-namespace");
 * // The record is still stored in namespace "specific-namespace".
 * boundMemcache.put("key3", "value3");
 * 
* *

MemcacheService {@code memcache} (in the above example) uses the current * namespace and {@code key1} will be stored in namespace {@code "a-namespace"}, * while {@code key2} is stored in namespace {@code "other-namespace"}. It is * possible to override the current namespace and store data in specific * namespace. In the above example {@code key3} is stored in namespace * {@code "specific-namespace"}. * *

The Task Queue {@link com.google.appengine.api.taskqueue.Queue#add} * methods will forward the {@link NamespaceManager} settings into the task * being added causing the added task to be executed with the same current * namespace as the task creator. The exception is that an unset current * namespace (i.e. {@link NamespaceManager#get()} returns null) will be * forwarded as an empty ("") namespace to the created task's requests. * * @see * Multitenancy and the Namespaces Java API. In Google App Engine * Developer's Guide. */ public final class NamespaceManager { // Namespace string valid pattern matcher. // See http://b/2104357 for a discussion of choice of format. // Note: Keep this consistent with the Python namespace_manager and // apphosting/base/id_util.cc. private final static int NAMESPACE_MAX_LENGTH = 100; private final static String NAMESPACE_REGEX = "[0-9A-Za-z._-]{0," + NAMESPACE_MAX_LENGTH +"}"; private static final Pattern NAMESPACE_PATTERN = Pattern.compile(NAMESPACE_REGEX); /** * We store the current namespace as an environment attribute identified * by this key. */ // Keep these in sync with other occurrences. private static final String CURRENT_NAMESPACE_KEY = NamespaceManager.class.getName() + ".currentNamespace"; private static final String APPS_NAMESPACE_KEY = NamespaceManager.class.getName() + ".appsNamespace"; /** * Set the value used to initialize the namespace of namespace-aware services. * * @param newNamespace the new namespace. * @throws IllegalArgumentException if namespace string is invalid. */ public static void set(String newNamespace) { ApiProxy.Environment environment = ApiProxy.getCurrentEnvironment(); if (newNamespace == null) { if (environment != null) { environment.getAttributes().remove(CURRENT_NAMESPACE_KEY); } } else { validateNamespace(newNamespace); if (environment == null) { // IllegalStateException would make more sense, but this is compatible with code that // detected the absence of an environment by the NullPointerException it provoked due // to unprotected dereferences of `environment` in earlier versions. throw new NullPointerException( "Operation not allowed in a thread that is neither the original request thread " + "nor a thread created by ThreadManager"); } // store this value as an attribute in the environment environment.getAttributes().put(CURRENT_NAMESPACE_KEY, newNamespace); } } /** *Returns the current namespace setting or either {@code null} or "" (empty) if not set. * *

If the current namespace is unset, callers should assume * the use of the "" (empty) namespace in all namespace-aware services. */ public static String get() { return getNamespaceForKey(CURRENT_NAMESPACE_KEY); } /** * Returns the Google Apps domain referring this request or * otherwise the empty string (""). */ public static String getGoogleAppsNamespace() { String appsNamespace = getNamespaceForKey(APPS_NAMESPACE_KEY); return appsNamespace == null ? "" : appsNamespace; } private static String getNamespaceForKey(String key) { ApiProxy.Environment environment = ApiProxy.getCurrentEnvironment(); if (environment == null) { return null; } else { return (String) environment.getAttributes().get(key); } } /** * Validate the format of a namespace string. * @throws IllegalArgumentException If the format of the namespace string * is invalid. */ public static void validateNamespace(String namespace) { if (!NAMESPACE_PATTERN.matcher(namespace).matches()) { throw new IllegalArgumentException( "Namespace '" + namespace + "' does not match pattern '" + NAMESPACE_PATTERN + "'."); } } // Make unconstructible. private NamespaceManager() { } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy