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 Sling, JCR e OSGi. Se o AEM não fornecer uma API, prefira Sling sobre 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, AEM PageManager e Página As APIs fornecem abstrações para cq:Page
nós no AEM que representam páginas da Web.
Enquanto esses nós estiverem disponíveis via Sling APIs como Recursos e APIs JCR 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
A variável com.adobe.cq
O pacote aceita casos de uso de produtos, enquanto com.adobe.granite
O oferece suporte a casos de uso de plataformas entre produtos, como fluxo de trabalho ou tarefas (que são usados em produtos: AEM Assets, Sites e assim por diante).
A variável com.day.cq
O pacote contém APIs "originais". Essas APIs abordam abstrações e funcionalidades principais que existiam antes e/ou em torno da aquisição da Adobe Day CQ. Essas APIs são compatíveis e devem ser evitadas, a menos que com.adobe.cq
ou com.adobe.granite
O não fornece 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 consulta
O AEM oferece suporte a vários idiomas de consulta. Os três idiomas principais são JCR-SQL2, XPath e Construtor de consulta 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.
Todos os idiomas de consulta têm efetivamente os mesmos perfis de desempenho, como Apache Oak empilha-os em JCR-SQL2 para execução final de consulta, e o tempo de conversão para JCR-SQL2 é insignificante em comparação ao próprio tempo de consulta.
A API preferida é Construtor de consulta 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 para consultas, e fornece o seguinte:
-
Construção de consulta simples e parametrizada (parâmetros de consulta modelados como um Mapa)
-
Nativo APIs Java™ e HTTP
-
Predicados do AEM suporte a requisitos comuns de consulta
-
API extensível, permitindo o desenvolvimento de aplicativos predicados de consulta
-
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 que respalda o AEM. Sling O fornece roteamento de solicitações HTTP, nós JCR de modelos como recursos, fornece contexto de segurança e muito mais.
Sling As APIs têm a vantagem adicional de serem criadas para extensão, o que significa que geralmente é mais fácil e seguro aumentar o comportamento de aplicativos criados usando o Sling APIs do que as menos extensíveis APIs JCR.
Usos comuns do Sling APIs
-
Acessando nós JCR como Sling Resources e acesso aos seus dados via ValueMaps.
-
Fornecer contexto de segurança por meio do ResourceResolver.
-
Criação e remoção de recursos por meio do ResourceResolver's criar/mover/copiar/excluir métodos.
-
Atualização de propriedades por meio da ModisibleValueMap.
-
Processamento de solicitação de construção de blocos de construção
-
Blocos de construção de processamento de trabalho assíncrono
APIs JCR
A variável APIs JCR (Java™ Content Repository) 2.0 é parte de uma especificação para implementações JCR (no caso de 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 sejam preferidos em relação ao AEM de nível mais alto e Sling abstrações.
Sempre prefira as APIs JCR às APIs Apache Jackrabbit Oak. As APIs 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 APIs JCR
Embora o JCR seja um repositório de conteú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, Ativos, 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 do 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 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 do AEM OSGi, Apache Felix, também fornece várias de suas próprias APIs.
- Preferir APIs OSGi (
org.osgi
) sobre APIs Apache Felix (org.apache.felix
).
Usos comuns de APIs OSGi
-
Anotações OSGi para declarar serviços e componentes OSGi.
- Preferir Anotações do OSGi Declarative Services (DS) 1.2 sobre Felix SCR Anotações para declarar serviços e componentes OSGi
-
APIs OSGi para codificação dinâmica cancelamento/registro de serviços/componentes OSGi.
- 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 pelo org.osgi
são preferíveis sobre abstrações Sling de nível superior. As abstrações Sling concorrentes não foram marcadas como @Deprecated
e sugerir a org.osgi
alternativa.
Observe também que a definição do nó de configuração OSGi prefere cfg.json
sobre o sling:OsgiConfig
formato.
APIs de ativos AEM
-
Preferir
com.day.cq.dam.api
sobrecom.adobe.granite.asset.api
.- Embora a
com.day.cq
As APIs de ativos fornecem ferramentas mais complementares para 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 a
APIs de consulta
- O AEM QueryBuilder não é compatível com 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.
Sling Registro de servlet sling-servlet-registration
- Sling registro de servlet, prefira Anotações do OSGi DS 1.2 com @SlingServletResourceTypes sobre
@SlingServlet
Sling Filtrar registro sling-filter-registration
- Sling registro de filtro, preferir Anotações do OSGi DS 1.2 com @SlingServletFilter sobre
@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, a Sling ResourceResolver é AutoClosable
em um try-with-resources declaração. Usando essa 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 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 ativo AEM
Método recomendado
A variável DamUtil.resolveToAsset(..)
resolve qualquer recurso na variável dam:Asset
ao objeto de Ativo, subindo na árvore, conforme necessário.
Asset asset = DamUtil.resolveToAsset(resource);
Abordagem alternativa
Adaptar um recurso a um Ativo exige que o próprio recurso seja o dam:Asset
nó.
Asset asset = resource.adaptTo(Asset.class);
Sling Recurso para página AEM
Método recomendado
pageManager.getContainingPage(..)
resolve qualquer recurso no cq:Page
ao objeto Page, 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 exige que o próprio recurso seja o cq:Page
nó.
Page page = resource.adaptTo(Page.class);
Ler propriedades da página AEM
Use os getters do objeto Page para obter propriedades bem conhecidas (getTitle()
, getDescription()
e assim por diante) e page.getProperties()
para obter a [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 propriedades de metadados de ativos do AEM
A API de ativos fornece métodos convenientes para a leitura de propriedades da [dam:Asset]/jcr:content/metadata
nó. 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 Sling Resource propriedades read-sling-resource-properties
Quando as propriedades são armazenadas em locais (propriedades ou recursos relativos) nos quais as APIs do AEM (Página, Ativo) não podem acessar diretamente, a variável Sling Resources 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 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 SlingModifiedValueMap de
Uso Slingdo ModisibleValueMap para gravar propriedades em nós. Isso só pode gravar no nó imediato (caminhos de propriedade relativos não são compatíveis).
Observe a chamada para .adaptTo(ModifiableValueMap.class)
exige permissões de gravação para o recurso, caso contrário, retorna 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 Sling Recurso
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, Ativos, 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 Sling Recurso
ResourceResolver dá suporte à remoção de um recurso. Ao criar abstrações de nível superior (Páginas AEM, Ativos, Tags e assim por diante), use os métodos fornecidos pelos respectivos Gerentes.
resourceResolver.delete(resource);
resourceResolver.commit();