Com a API Namespaces, você ativa facilmente a multilocação no aplicativo. Basta selecionar uma string de namespace para cada locatário em web.xml
usando o pacote NamespaceManager
.
Como definir o namespace atual
É possível receber, definir e validar namespaces usando NamespaceManager
. O gerenciador de namespaces permite definir um namespace atual para APIs ativadas para namespace. Um namespace que você define antecipadamente usando web.xml
é usado automaticamente pelo armazenamento de dados e pelo Memcache.
A maioria dos desenvolvedores do App Engine usa o próprio domínio do Google Workspace (antigo G Suite) como namespace atual. Com o Google Workspace, é possível implantar o app em qualquer domínio próprio. Portanto, esse mecanismo pode ser facilmente usado para configurar namespaces diferentes para domínios distintos. Em seguida, use esses namespaces separados para segregar dados entre os domínios. Para saber mais, consulte Como mapear domínios personalizados.
Veja no exemplo de código a seguir como definir o namespace atual no domínio do Google Workspace que foi usado para mapear o URL. Essa string será a mesma para todos os URLs mapeados por meio do mesmo domínio do Google Workspace.
É possível definir namespaces em Java usando a interface de filtro do servlet antes de chamar os métodos do servlet. O exemplo simples a seguir demonstra como usar o domínio do Google Workspace como namespace atual:
É preciso configurar o filtro de namespace no arquivo web.xml
. Observe que, se houver várias entradas de filtro, o primeiro namespace a ser definido será o usado.
O seguinte exemplo de código demonstra como configurar o filtro de namespace em web.xml
:
Para mais informações gerais sobre o arquivo web.xml
e o mapeamento de caminhos de URL para servlets, consulte O descritor de implantação: web.xml
.
Também é possível definir um novo namespace para uma operação temporária. Para isso, redefina o namespace original após a conclusão da operação usando o padrão try
/finally
mostrado abaixo:
Se você não especificar um valor para namespace
, o namespace será definido como uma string vazia. A string namespace
é arbitrária, mas também limitada a um máximo de 100 caracteres alfanuméricos, pontos, sublinhados e hifens. Mais explicitamente, strings de namespace precisam corresponder à expressão regular [0-9A-Za-z._-]{0,100}
.
Por convenção, todos os namespaces que começam com "_
" (sublinhado) são reservados para uso do sistema. Essa regra de namespaces do sistema não é obrigatória, mas será fácil encontrar consequências negativas indefinidas se você não a seguir.
Como evitar vazamentos de dados
Um dos riscos comumente associados a aplicativos multilocatários é o perigo de que dados vazem entre namespaces. Os vazamentos de dados inesperados podem surgir de muitas fontes, como estas:
- Usar namespaces com APIs do App Engine que ainda não são compatíveis com namespaces. Por exemplo, o Blobstore não é compatível com namespaces. Se você usar Namespaces com o Blobstore, precisará evitar o uso de consultas Blobstore para solicitações de usuários finais ou chaves Blobstore de fontes não confiáveis.
- Usar um meio de armazenamento externo (em vez do Memcache e do armazenamento de dados), via
URL Fetch
ou algum outro mecanismo, sem fornecer um esquema de distribuição de namespaces. - Definir um namespace com base no domínio do e-mail de um usuário. Na maioria dos casos, não é desejável que todos os endereços de e-mail de um domínio tenham acesso a um namespace. Usar o domínio do e-mail também impede que o aplicativo use um namespace antes que o usuário faça login.
Como implantar namespaces
Veja nas seções a seguir como implantar namespaces com outras APIs e ferramentas do App Engine.
Como criar namespaces por usuário
Alguns aplicativos devem criar namespaces por usuário. Se você quiser distribuir dados no nível do usuário para usuários conectados, use User.getUserId()
, que retorna um ID permanente e exclusivo para o usuário. O exemplo de código a seguir demonstra como usar a API de usuários para esse fim:
Geralmente, nos aplicativos em que os namespaces são criados por usuário, páginas de destino específicas também são fornecidas para diferentes usuários. Nesses casos, o aplicativo deve fornecer um esquema de URL que dite qual página de destino exibir para um usuário.
Como usar namespaces com o Datastore
Por padrão, solicitações de armazenamento de dados no Datastore são feitas usando a configuração do namespace atual no gerenciador de namespaces. A API aplica esse namespace atual aos objetos Key
ou Query
quando eles são criados. Portanto, tome cuidado se um aplicativo armazenar objetos Key
ou Query
em formulários serializados, porque o namespace é mantido nessas serializações.
Se você estiver usando objetos Key
e Query
não serializados, verifique se eles se comportam conforme o esperado. A maioria dos aplicativos simples que usam armazenamento de dados (put
/query
/get
) sem usar outros mecanismos de armazenamento funcionarão como esperado, se você definir o namespace atual antes de chamar qualquer API do armazenamento de dados.
Os objetos Query
e Key
demonstram os seguintes comportamentos exclusivos em relação aos namespaces:
- Os objetos
Query
eKey
herdam o namespace atual quando criados, a menos que você defina um namespace explícito. - Quando um aplicativo cria um novo
Key
de um ancestral, o novoKey
herda o namespace do ancestral. - Não há API de Java para definir explicitamente o namespace de um
Key
ouQuery
.
SomeRequest
para incrementar a contagem do namespace atual e o namespace -global-
nomeado arbitrariamente em uma entidade de armazenamento de dados Counter
.
Como usar namespaces com o Memcache
Por padrão, o memcache usa o namespace atual do gerenciador de namespaces para solicitações do memcache. Na maioria dos casos, você não precisa definir um namespace explicitamente no memcache. Fazer isso pode causar bugs inesperados.
Entretanto, há algumas ocasiões específicas em que é adequado definir um namespace explicitamente no memcache. Por exemplo, o aplicativo pode ter dados em comum compartilhados entre todos os namespaces (como uma tabela contendo códigos de países).
Veja no snippet de código abaixo como definir o namespace explicitamente no memcache:
Por padrão, a API Memcache para Java consulta o gerenciador de namespaces quanto ao
namespace atual de MemcacheService
. Também é possível afirmar explicitamente um
namespace ao construir o memcache usando getMemcacheService(Namespace)
.
Para a maioria dos aplicativos, não é necessário especificar explicitamente um namespace.
O seguinte exemplo de código demonstra como criar um memcache que usa o namespace atual no gerente de namespace.
Esse exemplo de código especifica explicitamente um namespace ao criar um serviço de memcache:
Como usar namespaces com a fila de tarefas
Por padrão, as filas push usam o namespace atual configurado no administrador de namespaces no momento em que a tarefa foi criada. Na maioria dos casos, você não precisa definir um namespace explicitamente na fila de tarefas, e fazer isso pode gerar bugs inesperados.
Os nomes de tarefas são compartilhados com todos os namespaces. Não é possível criar duas tarefas com o mesmo nome, mesmo se usarem namespaces diferentes. Se quiser usar o mesmo nome de tarefa para vários namespaces, acrescente cada namespace ao nome da tarefa.
Quando uma nova tarefa chama o método add()
da fila de tarefas, essa fila copia o namespace atual e, se for o caso, o domínio do Google Workspace do gerenciador de namespaces. Quando a tarefa é executada, o namespace atual e o namespace do Google Workspace são restaurados.
Se o namespace atual não for definido na solicitação originadora (ou seja, se get()
retornar null
), a fila de tarefas definirá o namespace como ""
nas tarefas executadas.
Há algumas ocasiões específicas em que é adequado definir um namespace explicitamente para uma tarefa que funciona em vários namespaces. Por exemplo, é possível criar uma tarefa que agrega estatísticas de uso para todos os namespaces. Depois, você define o namespace da tarefa explicitamente. O exemplo de código a seguir demonstra como definir namespaces explicitamente com a fila de tarefas.
Primeiro, crie uma gerenciador da fila de tarefas que incremente a contagem em uma entidade de armazenamento de dados Counter
:
e
Em seguida, crie tarefas com um servlet:
Como usar namespaces com o Blobstore
O Blobstore não é segmentado por namespace. Para preservar um namespace no Blobstore, você precisa acessar o Blobstore usando um meio de armazenamento que considere namespaces (atualmente, apenas o memcache, o armazenamento de dados e a fila de tarefas). Por exemplo, se o Key
de um blob estiver armazenado em uma entidade de armazenamento de dados, será possível acessá-lo com um armazenamento de dados Key
ou Query
que reconheça o namespace.
Se o aplicativo estiver acessando o Blobstore por meio de chaves armazenadas em armazenamento que considera namespaces, então o próprio Blobstore não precisa ser segmentado por namespace. Aplicativos precisam evitar vazamentos de blobs entre namespaces:
- Não usando
com.google.appengine.api.blobstore.BlobInfoFactory
para solicitações de usuário final. Use as consultas BlobInfo para solicitações administrativas (como gerar relatórios sobre todos os blobs de aplicativos), mas usá-las para solicitações de usuários finais pode resultar em vazamentos de dados, porque os registros de BlobInfo não são compartimentados por namespace. - Não usar chaves do Blobstore de fontes não confiáveis.
Como definir namespaces para consultas ao Datastore
No console do Google Cloud, é possível definir o namespace para consultas do Datastore.
Se você não quiser usar o padrão, selecione o namespace desejado na lista suspensa.
Como usar namespaces com o carregador em massa
O carregador em lote aceita uma sinalização --namespace=NAMESPACE
que permite especificar o namespace a ser usado. Cada namespace é manipulado separadamente. Se quiser acessar todos os namespaces, itere-os.
Como usar namespaces na pesquisa
Uma nova instância de Index
herda o namespace do SearchService
usado para criá-la. Depois de criar uma referência a um índice, o namespace não pode ser alterado. Há duas maneiras de definir o namespace para um SearchService
antes de usá-lo para criar um índice:
- Por padrão, um novo
SearchService
assume o namespace atual. Você pode definir o namespace atual antes de criar o serviço:
É possível especificar um namespace no SearchServiceConfig
ao criar um serviço: