Práticas recomendadas da API Java

O Adobe Experience Manager (AEM) é criado em uma pilha rica 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.

AEM é criado em 4 conjuntos principais de APIs do Java.

  • Adobe Experience Manager (AEM)

    • abstrações de produto, como páginas, ativos, fluxos de trabalho etc.
  • Estrutura Web do Apache Sling

    • REST e abstrações baseadas em recursos, como recursos, mapas de valor e solicitações HTTP.
  • JCR (Apache Jackrabbit Oak)

    • abstrações de dados e conteúdo, como nó, propriedades e sessões.
  • OSGi (Apache Felix)

    • abstrações do contêiner de aplicativos OSGi, como serviços e componentes (OSGi).

Preferência da API Java "regra de ouro"

A regra geral é preferir as APIs/abstrações na seguinte ordem:

  1. AEM
  2. Sling
  3. JCR
  4. OSGi

Se uma API for fornecida pelo AEM, prefira-a em vez de Sling, JCR e OSGi. Se AEM não fornecer uma API, então preferir Sling sobre JCR e OSGi.

Essa ordem é uma regra geral, o que significa que existem exceções. Os motivos aceitáveis para quebrar 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 do código existente (código de produto personalizado ou AEM) que usa uma API menos preferencial e o custo para migrar para a nova API é injustificável.

    • É melhor usar consistentemente a API de nível inferior do que criar uma combinação.

AEM APIs

AEM APIs fornecem abstrações e funcionalidades específicas para casos de uso produzidos.

Por exemplo, AEM PageManager e Página As APIs fornecem abstrações para cq:Page nos AEM que representam páginas da Web.

Embora esses nós estejam disponíveis via Sling As APIs como Recursos e as APIs JCR como Nós, AEM APIs fornecem abstrações para casos de uso comuns. Usar as APIs de AEM garante um comportamento consistente entre AEM produto, além de personalizações e extensões para AEM.

com.adobe.* vs com.day.* APIs

AEM APIs têm uma preferência dentro do pacote, identificada pelos seguintes pacotes Java, em ordem de preferência:

  1. com.adobe.cq
  2. com.adobe.granite
  3. com.day.cq

com.adobe.cq suporta casos de uso de produtos, enquanto com.adobe.granite O suporta casos de uso de plataformas entre produtos, como fluxo de trabalho ou tarefas (que são usadas em produtos: AEM Assets, Sites etc.).

com.day.cq contém APIs "originais". Essas APIs abordam as principais abstrações e funcionalidades existentes antes e/ou em torno da aquisição Adobe de Day CQ. Essas APIs são compatíveis e não devem ser evitadas, a menos que com.adobe.cq ou com.adobe.granite forneça uma alternativa (mais recente).

Novas abstrações como Content Fragments e Experience Fragments são criados no com.adobe.cq espaço em vez de com.day.cq descrito abaixo.

APIs de query

AEM suporta vários idiomas de consulta. Os 3 principais idiomas são JCR-SQL2, XPath e AEM Query Builder.

A preocupação mais importante é manter uma linguagem de consulta consistente na base de código, para reduzir a complexidade e o custo de compreensão.

Todos os idiomas de consulta têm efetivamente os mesmos perfis de desempenho, como Apache Oak O os transpila para o JCR-SQL2 para a execução final da consulta, e o tempo de conversão para JCR-SQL2 é insignificante em comparação com o próprio tempo de consulta.

A API preferencial é AEM Query Builder, que é a abstração de mais alto nível e fornece uma API robusta para criar, executar e recuperar resultados para consultas, e fornece o seguinte:

ATENÇÃO

AEM API do QueryBuilder vaza um objeto ResourceResolver. Para mitigar esse vazamento, siga este amostra de código.

Sling APIs

Apache Sling é a estrutura Web RESTful que suporta AEM. Sling O fornece roteamento de solicitação HTTP, modela nós JCR como recursos, fornece contexto de segurança e muito mais.

Sling As APIs têm o benefício adicional de serem criadas para extensão, o que significa que geralmente é mais fácil e seguro aumentar o comportamento de aplicativos criados com Sling APIs do que as APIs JCR menos extensíveis.

Utilizações comuns de Sling APIs

APIs JCR

O APIs JCR (Java Content Repository) 2.0 faz parte de uma especificação para implementações do JCR (no caso de AEM, Apache Jackrabbit Oak). Toda implementação do JCR deve estar em conformidade e implementar essas APIs e, portanto, é a API de nível mais baixo para interagir com AEM conteúdo.

O próprio JCR é um armazenamento de dados NoSQL hierárquico/baseado em árvore AEM usa como seu repositório de conteúdo. O JCR tem uma grande variedade de APIs compatíveis, que vão de CRUD de conteúdo a query de conteúdo. Apesar dessa API robusta, é raro que eles sejam preferenciais em relação ao AEM de nível superior e Sling abstrações.

Sempre prefira as APIs JCR em vez das APIs do Apache Jackrabbit Oak. As APIs do JCR são para interação com um repositório JCR, enquanto as APIs do Oak são para implementação um repositório JCR.

Equívocos comuns sobre as APIs do JCR

Embora o JCR seja AEM repositório de conteúdo, suas APIs NÃO são o método preferido para interagir com o conteúdo. Em vez disso, prefere as APIs do AEM (Página, Ativos, Tag etc.) ou APIs de recursos do Sling, pois fornecem abstrações melhores.

ATENÇÃO

O uso amplo das interfaces Sessão e Nó das APIs de JCR em um aplicativo de AEM é fedor de código. Garantir Sling As APIs não devem ser usadas.

Uso comum de APIs JCR

APIs OSGi

Há pouca sobreposição entre as APIs OSGi e as APIs de nível superior (AEM, Slinge JCR), e a necessidade de usar APIs OSGi é rara e requer um alto nível de conhecimento AEM em desenvolvimento.

APIs OSGi vs Apache Felix

O OSGi define uma especificação para a qual todos os contêineres OSGi devem implementar e estar em conformidade. AEM implementação do OSGi, o Apache Felix, também fornece várias de suas próprias APIs.

  • Preferir APIs OSGi (org.osgi) sobre as APIs do Apache Felix (org.apache.felix).

Uso comum de APIs OSGi

Exceções à regra

As exceções a seguir são comuns às regras definidas acima.

APIs OSGi

Ao lidar com abstrações de baixo nível do OSGi, como definir ou ler nas propriedades do componente OSGi, as abstrações mais recentes fornecidas pelo org.osgi são preferíveis em vez de abrações Sling de nível superior. As abstrações Sling concorrentes não foram marcadas como @Deprecated e sugerir org.osgi alternativa.

Observe também a definição do nó de configuração OSGi preferir cfg.json sobre sling:OsgiConfig formato.

AEM APIs de ativos

  • Preferência com.day.cq.dam.api over com.adobe.granite.asset.api.

    • Enquanto a variável com.day.cq As APIs de ativos fornecem ferramentas mais complementares para AEM casos de uso do gerenciamento de ativos.
    • 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).

APIs de query

  • AEM QueryBuilder 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 essas funções com o JCR-SQL2.

Sling Registro do servlet

Sling Registro do filtro

Trechos úteis do código

Os itens a seguir são úteis trechos de código Java que ilustram as práticas recomendadas para casos de uso comuns usando APIs discutidas. Esses trechos também ilustram como migrar de APIs menos preferenciais para APIs mais preferidas.

Sessão JCR para Sling ResourceResolver

Fechamento automático do Sling ResourceResolver

Desde o AEM 6.2, a variável Sling ResourceResolver é AutoClosable em usar recursos instrução. Usando essa sintaxe, uma chamada explícita para resourceResolver .close() não é necessário.

@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 finally bloco , 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 ativo

Abordagem recomendada

DamUtil.resolveToAsset(..)resolve qualquer recurso sob o dam:Asset para o objeto Ativo, subindo a árvore conforme necessário.

Asset asset = DamUtil.resolveToAsset(resource);

Abordagem alternativa

A adaptação de um recurso a um ativo requer que o próprio recurso seja o dam:Asset nó .

Asset asset = resource.adaptTo(Asset.class);

Sling Recurso para AEM página

Abordagem recomendada

pageManager.getContainingPage(..) resolve qualquer recurso sob o cq:Page para o objeto Page , suba a á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

A adaptação de um recurso a uma Página exige que o próprio recurso seja o cq:Page nó .

Page page = resource.adaptTo(Page.class);

Ler AEM Propriedades da página

Use os getters do objeto Page para obter propriedades conhecidas (getTitle(), getDescription(), etc.) e page.getProperties() para obter [cq:Page]/jcr:content ValueMap para recuperar outras propriedades.

Page page = resource.adaptTo(Page.class);
String title = page.getTitle();
Calendar value = page.getProperties().get("cq:lastModified", Calendar.getInstance());

Ler AEM propriedades de metadados de ativos

A API de ativo fornece métodos convenientes para a leitura de propriedades do [dam:Asset]/jcr:content/metadata nó . Observe que este não é um ValueMap, o segundo parâmetro (valor padrão e transmissão de tipo automático) não é suportado.

Asset asset = resource.adaptTo(Asset.class);
String title = asset.getMetadataValue("dc:title");
Calendar lastModified = (Calendar) asset.getMetadata("cq:lastModified");

Ler Sling Resource propriedades

Quando as propriedades são armazenadas em locais (propriedades ou recursos relativos) em que as APIs de AEM (Página, Ativo) não podem acessar diretamente, a variável Sling Recursos e ValueMaps 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 subrecurso desejado.

AEM página para Sling Resource

Resource resource = page.adaptTo(Resource.class);

AEM ativo para Sling Resource

Resource resource = asset.adaptTo(Resource.class);

Gravar propriedades usando Sling's ModiABLEValueMap

Use Sling's ValueMap modificável para gravar propriedades em nós. Isso só pode gravar no nó imediato (os caminhos de propriedade relativos não são compatíveis).

Observe a chamada para .adaptTo(ModifiableValueMap.class) requer permissões de gravação para o recurso; caso contrário, retornará null.

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 de AEM

Sempre use o PageManager para criar páginas conforme ele utiliza 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(); }

Crie um Sling Recurso

O ResourceResolver oferece suporte a operações básicas para a criação de recursos. Ao criar abstrações de nível superior (Páginas de AEM, Ativos, Tags etc.) utilizar 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 Sling Recurso

O ResourceResolver suporta a remoção de um recurso. Ao criar abstrações de nível superior (Páginas de AEM, Ativos, Tags etc.) utilizar os métodos fornecidos pelos respectivos Gerentes.

resourceResolver.delete(resource);

resourceResolver.commit();

Nesta página