Práticas recomendadas da API Java™
O Adobe Experience Manager (AEM) é construído em uma pilha avançada de software de código aberto que expõe muitas APIs Java™ para uso durante o desenvolvimento. Este artigo explora as principais APIs e quando e por que elas devem ser usadas.
O AEM é construído em quatro conjuntos principais de APIs Java™.
-
Adobe Experience Manager (AEM)
- Abstrações de produto, como páginas, ativos, fluxos de trabalho etc.
-
Apache Sling Web Framework
- REST e abstrações baseadas em recursos, como recursos, mapas de valores e solicitações HTTP.
-
JCR (Apache Jackrabbit Oak)
- Dados e abstrações de conteúdo, como nó, propriedades e sessões.
-
OSGi (Apache Felix)
- Abstrações do contêiner de aplicativo OSGi, como serviços e componentes (OSGi).
Preferência da API Java™ "regra geral"
A regra geral é preferir as APIs/abstrações na seguinte ordem:
- AEM
- Sling
- JCR
- OSGi
Se uma API for fornecida pelo AEM, prefira ela a Sling, JCR e OSGi. Se o AEM não fornecer uma API, prefira Sling a JCR e OSGi.
Essa ordem é uma regra geral, o que significa que existem exceções. Os motivos aceitáveis para romper com essa regra são:
-
Exceções bem conhecidas, conforme descrito abaixo.
-
A funcionalidade necessária não está disponível em uma API de nível superior.
-
Operar no contexto de código existente (código de produto personalizado ou AEM) que usa uma API menos preferencial, e o custo de mover para a nova API é injustificável.
- É melhor usar de forma consistente a API de nível inferior do que criar uma combinação.
APIs AEM
As APIs do AEM fornecem abstrações e funcionalidades específicas para casos de uso produzidos.
Por exemplo, as APIs de PageManager e Page do AEM fornecem abstrações para nós cq:Page
no AEM que representam páginas da Web.
Embora esses nós estejam disponíveis por meio de Sling APIs como Recursos e JCR APIs como Nós, as APIs AEM fornecem abstrações para casos de uso comuns. Usar as APIs do AEM garante um comportamento consistente entre o AEM e as personalizações e extensões do AEM.
com.adobe.* vs. com.day.* APIs
As APIs AEM têm uma preferência dentro do pacote, identificada pelos seguintes pacotes Java™, em ordem de preferência:
com.adobe.cq
com.adobe.granite
com.day.cq
O pacote com.adobe.cq
oferece suporte a casos de uso de produtos, enquanto o com.adobe.granite
oferece suporte a casos de uso de plataformas entre produtos, como fluxo de trabalho ou tarefas (que são usadas em produtos: AEM Assets, Sites e assim por diante).
O pacote com.day.cq
contém APIs "originais". Essas APIs abordam abstrações e funcionalidades principais que existiam antes e/ou em torno da aquisição de Day CQ pelo Adobe. Essas APIs são suportadas e devem ser evitadas, a menos que os pacotes com.adobe.cq
ou com.adobe.granite
NÃO forneçam uma alternativa (mais recente).
Novas abstrações, como Content Fragments e Experience Fragments, são criadas no espaço com.adobe.cq
em vez de com.day.cq
, conforme descrito abaixo.
APIs de consulta
O AEM oferece suporte a vários idiomas de consulta. Os três idiomas principais são JCR-SQL2, XPath e Construtor de Consultas do AEM.
A preocupação mais importante é manter uma linguagem de consulta consistente em toda a base de código, para reduzir a complexidade e os custos de compreensão.
Todas as linguagens de consulta têm efetivamente os mesmos perfis de desempenho, já que Apache Oak as compila para JCR-SQL2 para execução de consulta final, e o tempo de conversão para JCR-SQL2 é insignificante em comparação ao próprio tempo de consulta.
A API preferida é o Construtor de Consultas AEM, que é a abstração de mais alto nível e fornece uma API robusta para construção, execução e recuperação de resultados de consultas, além de fornecer o seguinte:
-
Construção de consulta simples e parametrizada (parâmetros de consulta modelados como um Mapa)
-
Predicados AEM com suporte a requisitos de consulta comuns
-
API extensível, permitindo o desenvolvimento de predicados de consulta personalizados
-
JCR-SQL2 e XPath podem ser executados diretamente por meio de Sling e APIs JCR, retornando resultados como Sling Recursos ou Nós JCR, respectivamente.
Sling APIs
Apache Sling é a estrutura da Web RESTful subjacente ao AEM. Sling fornece roteamento de solicitações HTTP, modela nós JCR como recursos, fornece contexto de segurança e muito mais.
Sling APIs têm a vantagem adicional de serem compiladas para extensão, o que significa que geralmente é mais fácil e seguro aumentar o comportamento de aplicativos compilados usando APIs Sling do que as APIs JCR menos extensíveis.
Usos comuns de Sling APIs
-
Acessando nós JCR como Sling Resources e acessando seus dados via ValueMaps.
-
Fornecendo contexto de segurança via ResourceResolver.
-
Criando e removendo recursos por meio dos métodos create/move/copy/delete de ResourceResolver.
-
Atualizando propriedades por meio de ModifiedValueMap.
-
Processamento de solicitação de construção de blocos de construção
-
Blocos de construção de processamento de trabalho assíncrono
APIs JCR
As APIs do JCR (Java™ Content Repository) 2.0 fazem parte de uma especificação das implementações do JCR (no caso do AEM, Apache Jackrabbit Oak). Toda implementação do JCR deve estar em conformidade com e implementar essas APIs, e, portanto, é a API de nível mais baixo para interagir com o conteúdo do AEM.
O próprio JCR é um armazenamento de dados NoSQL hierárquico/em árvore que o AEM usa como seu repositório de conteúdo. O JCR tem uma grande variedade de APIs compatíveis, que vão desde a CRUD de conteúdo até a consulta de conteúdo. Apesar dessa API robusta, é raro que eles sejam preferidos em relação ao AEM de nível mais alto e Sling abstrações.
Sempre prefira as APIs JCR às APIs do Apache Jackrabbit Oak. As APIs JCR são para interagir com um repositório JCR, enquanto as APIs do Oak são para implementar um repositório JCR.
Equívocos comuns sobre APIs JCR
Embora o JCR seja o repositório de conteúdo do AEM, suas APIs NÃO são o método preferido para interagir com o conteúdo. Em vez disso, prefira as APIs de AEM (Página, Assets, Tag e assim por diante) ou as APIs de recurso do Sling, pois fornecem melhores abstrações.
Usos comuns de APIs JCR
-
Observação JCR (escutando eventos JCR)
-
Criação de estruturas de nó profundo
APIs OSGi
Há pouca sobreposição entre as APIs OSGi e as APIs de nível superior (AEM, Sling e JCR), e a necessidade de usar APIs OSGi é rara e requer um alto nível de conhecimento em desenvolvimento de AEM.
OSGi versus APIs Apache Felix
O OSGi define uma especificação que todos os contêineres OSGi devem implementar e estar em conformidade. A implementação OSGi do AEM, Apache Felix, também fornece várias de suas próprias APIs.
- Preferir APIs OSGi (
org.osgi
) a APIs Apache Felix (org.apache.felix
).
Usos comuns de APIs OSGi
-
Anotações OSGi para declarar serviços e componentes OSGi.
- Preferir Anotações 1.2 do OSGi Declarative Services (DS) a Anotações Felix SCR para declarar serviços e componentes OSGi
-
APIs OSGi para componentes/serviços OSGi dinamicamente no código desfazer/registrar.
- Prefira o uso de anotações OSGi DS 1.2 quando o gerenciamento condicional de serviço/componente OSGi não for necessário (o que geralmente ocorre).
Exceções à regra
Veja a seguir exceções comuns às regras definidas acima.
APIs OSGi
Ao lidar com abstrações OSGi de baixo nível, como definir ou ler nas propriedades do componente OSGi, as abstrações mais recentes fornecidas por org.osgi
são preferíveis em relação às abstrações Sling de nível superior. As abstrações Sling concorrentes não foram marcadas como @Deprecated
e sugerem a alternativa org.osgi
.
Observe também que a definição do nó de configuração OSGi prefere cfg.json
ao formato sling:OsgiConfig
.
APIs de ativos AEM
-
Preferir
com.day.cq.dam.api
acom.adobe.granite.asset.api
.- Embora as APIs do Assets
com.day.cq
forneçam ferramentas mais complementares para os casos de uso de gerenciamento de ativos do AEM. - As APIs do Granite Assets são compatíveis com casos de uso de gerenciamento de ativos de baixo nível (versão, relações).
- Embora as APIs do Assets
APIs de consulta
- O Construtor de Consultas AEM não oferece suporte a determinadas funções de consulta, como sugestões, verificação ortográfica e dicas de índice, entre outras funções menos comuns. É preferível consultar com essas funções o JCR-SQL2.
Registro do Servlet Sling sling-servlet-registration
- Registro do servlet Sling, prefira as anotações OSGi DS 1.2 com @SlingServletResourceTypes a
@SlingServlet
Registro de filtro Sling sling-filter-registration
- Sling registro de filtro, prefira anotações do OSGi DS 1.2 com @SlingServletFilter a
@SlingFilter
Trechos de código úteis
A seguir estão trechos de código Java™ úteis que ilustram as práticas recomendadas para casos de uso comuns usando APIs discutidas. Esses fragmentos também ilustram como mover de APIs menos preferenciais para APIs mais preferenciais.
Sessão JCR para Sling ResourceResolver
Fechamento automático do Sling ResourceResolver
Desde o AEM 6.2, o ResourceResolver Sling é AutoClosable
em uma instrução try-with-resources. Usando esta sintaxe, uma chamada explícita para resourceResolver .close()
não é necessária.
@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);
try (ResourceResolver resourceResolver = rrf.getResourceResolver(authInfo)) {
// Do work with the resourceResolver
} catch (LoginException e) { .. }
Sling ResourceResolver fechado manualmente
ResourceResolvers pode ser fechado manualmente em um bloco finally
, se a técnica de fechamento automático mostrada acima não puder ser usada.
@Reference
ResourceResolverFactory rrf;
...
Map<String, Object> authInfo = new HashMap<String, Object>();
authInfo.put(JcrResourceConstants.AUTHENTICATION_INFO_SESSION, jcrSession);
ResourceResolver resourceResolver = null;
try {
resourceResolver = rrf.getResourceResolver(authInfo);
// Do work with the resourceResolver
} catch (LoginException e) {
...
} finally {
if (resourceResolver != null) { resourceResolver.close(); }
}
Caminho JCR para Sling Resource
Resource resource = ResourceResolver.getResource("/path/to/the/resource");
Nó JCR para Sling Resource
Resource resource = resourceResolver.getResource(node.getPath());
Sling Resource para AEM Asset
Método recomendado
A função DamUtil.resolveToAsset(..)
resolve qualquer recurso sob dam:Asset
para o objeto de Ativo, subindo na árvore, conforme necessário.
Asset asset = DamUtil.resolveToAsset(resource);
Abordagem alternativa
Adaptar um recurso a um Ativo requer que o próprio recurso seja o nó dam:Asset
.
Asset asset = resource.adaptTo(Asset.class);
Página de Sling recurso para AEM
Método recomendado
pageManager.getContainingPage(..)
resolve qualquer recurso sob cq:Page
para o objeto Página, subindo na árvore, conforme necessário.
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page page = pageManager.getContainingPage(resource);
Page page2 = pageManager.getContainingPage("/content/path/to/page/jcr:content/or/component");
Abordagem alternativa alternative-approach-1
Adaptar um recurso a uma Página requer que o próprio recurso seja o nó cq:Page
.
Page page = resource.adaptTo(Page.class);
Ler propriedades da página AEM
Use os getters do objeto Page para obter propriedades conhecidas (getTitle()
, getDescription()
e assim por diante) e page.getProperties()
para obter o ValueMap [cq:Page]/jcr:content
para recuperar outras propriedades.
Page page = resource.adaptTo(Page.class);
String title = page.getTitle();
Calendar value = page.getProperties().get("cq:lastModified", Calendar.getInstance());
Ler propriedades de metadados de ativos do AEM
A API de Ativo fornece métodos convenientes para a leitura de propriedades do nó [dam:Asset]/jcr:content/metadata
. Este não é um ValueMap, o segundo parâmetro (valor padrão e conversão de tipo automático) não é compatível.
Asset asset = resource.adaptTo(Asset.class);
String title = asset.getMetadataValue("dc:title");
Calendar lastModified = (Calendar) asset.getMetadata("cq:lastModified");
Ler propriedades de Sling Resource read-sling-resource-properties
Quando as propriedades são armazenadas em locais (propriedades ou recursos relativos) onde as APIs do AEM (Página, Ativo) não podem acessar diretamente, os Recursos do Sling e os Mapas de Valores podem ser usados para obter os dados.
ValueMap properties = resource.getValueMap();
String value = properties.get("jcr:title", "Default title");
String relativeResourceValue = properties.get("relative/propertyName", "Default value");
Nesse caso, o objeto AEM pode ter que ser convertido em um Sling Resource para localizar com eficiência a propriedade ou o sub-recurso desejado.
Página AEM para Sling Resource
Resource resource = page.adaptTo(Resource.class);
Ativo AEM para Sling Resource
Resource resource = asset.adaptTo(Resource.class);
Gravar propriedades usando ModisibleValueMap de Sling
Use ModisibleValueMap de Sling para gravar propriedades em nós. Isso só pode gravar no nó imediato (caminhos de propriedade relativos não são compatíveis).
Observe que a chamada para .adaptTo(ModifiableValueMap.class)
requer permissões de gravação para o recurso, caso contrário, ela retornará um valor nulo.
ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);
properties.put("newPropertyName", "new value");
properties.put("propertyNameToUpdate", "updated value");
properties.remove("propertyToRemove");
resource.getResourceResolver().commit();
Criar uma página AEM
Sempre use o PageManager para criar páginas, pois ele precisa de um Modelo de página, é necessário para definir e inicializar páginas corretamente no AEM.
String templatePath = "/conf/my-app/settings/wcm/templates/content-page";
boolean autoSave = true;
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
pageManager.create("/content/parent/path", "my-new-page", templatePath, "My New Page Title", autoSave);
if (!autoSave) { resourceResolver.commit(); }
Criar um recurso Sling
O ResourceResolver dá suporte a operações básicas para a criação de recursos. Ao criar abstrações de nível superior (Páginas AEM, Assets, Tags e assim por diante), use os métodos fornecidos pelos respectivos Gerentes.
resourceResolver.create(parentResource, "my-node-name", new ImmutableMap.Builder<String, Object>()
.put("jcr:primaryType", "nt:unstructured")
.put("jcr:title", "Hello world")
.put("propertyName", "Other initial properties")
.build());
resourceResolver.commit();
Excluir um recurso Sling
ResourceResolver dá suporte à remoção de um recurso. Ao criar abstrações de nível superior (Páginas AEM, Assets, Tags e assim por diante), use os métodos fornecidos pelos respectivos Gerentes.
resourceResolver.delete(resource);
resourceResolver.commit();