Prácticas recomendadas de API de Java

Adobe Experience Manager (AEM) se basa en una rica pila de software de código abierto que expone muchas API de Java para su uso durante el desarrollo. Este artículo explora las API principales y cuándo y por qué deben usarse.

AEM se basa en 4 conjuntos principales de API de Java.

  • Adobe Experience Manager (AEM)

    • abstracciones de productos, como páginas, recursos, flujos de trabajo, etc.
  • Apache Sling Web Framework

    • REST y abstracciones basadas en recursos, como recursos, mapas de valores y solicitudes HTTP.
  • JCR (Apache Jackrabbit Oak)

    • Abstracciones de datos y contenido, como nodos, propiedades y sesiones.
  • OSGi (Apache Felix)

    • abstracciones de contenedores de aplicaciones OSGi como servicios y componentes (OSGi).

Preferencia de la API de Java "regla general"

La regla general es preferir las API/abstracciones en el siguiente orden:

  1. AEM
  2. Sling
  3. JCR
  4. los paquetes

Si AEM proporciona una API, preferirla Sling, JCR y OSGi. Si AEM no proporciona una API, prefiera Sling sobre JCR y OSGi.

Este orden es una regla general, lo que significa que existen excepciones. Los motivos aceptables para romper con esta regla son:

  • Excepciones bien conocidas, como se describe a continuación.

  • La funcionalidad requerida no está disponible en una API de nivel superior.

  • Operar en el contexto de código existente (código de producto personalizado o AEM) que en sí mismo utiliza una API menos preferida, y el coste de pasar a la nueva API es injustificable.

    • Es mejor utilizar la API de nivel inferior de forma consistente que crear una mezcla.

API de AEM

AEM API proporcionan abstracciones y funciones específicas de los casos de uso productizados.

Por ejemplo, AEM PageManager y Página Las API proporcionan abstracciones para cq:Page nodos de AEM que representan páginas web.

Aunque estos nodos están disponibles mediante Sling Las API como recursos y las API de JCR como nodos, AEM API proporcionan abstracciones para casos de uso comunes. El uso de las API de AEM garantiza un comportamiento coherente entre AEM producto y las personalizaciones y extensiones de AEM.

com.adobe.* vs. com.day.* API

AEM API tienen una preferencia dentro del paquete, identificada por los siguientes paquetes Java, en orden de preferencia:

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

com.adobe.cq admite casos de uso de productos cuando com.adobe.granite admite casos de uso en plataformas de varios productos, como flujos de trabajo o tareas (que se utilizan en todos los productos: AEM Assets, Sitios, etc.).

com.day.cq contiene API "originales". Estas API tratan de abstracciones y funcionalidades básicas que existían antes o alrededor de la adquisición de Adobe de Day CQ. Estas API son compatibles y no deben evitarse, a menos que com.adobe.cq o com.adobe.granite proporcione una alternativa (más reciente).

Nuevas abstracciones como Content Fragments y Experience Fragments están incorporadas en la variable com.adobe.cq espacio en lugar de com.day.cq a continuación.

API de consulta

AEM admite varios idiomas de consulta. Los tres idiomas principales son JCR-SQL2, XPath y AEM Query Builder.

La preocupación más importante es mantener un lenguaje de consulta consistente en toda la base de código, para reducir la complejidad y el coste de comprensión.

Todos los idiomas de consulta tienen efectivamente los mismos perfiles de rendimiento que Apache Oak los transfiere a JCR-SQL2 para la ejecución de la consulta final, y el tiempo de conversión a JCR-SQL2 es insignificante comparado con el tiempo de consulta en sí.

La API preferida es AEM Query Builder, que es la abstracción de nivel más alto y proporciona una API sólida para construir, ejecutar y recuperar resultados para consultas, y proporciona lo siguiente:

PRECAUCIÓN

AEM API de QueryBuilder filtra un objeto ResourceResolver. Para mitigar esta fuga, siga este ejemplo de código.

Sling API

Apache Sling es el marco web de RESTful que AEM sustenta. Sling proporciona enrutamiento de solicitud HTTP, modela nodos JCR como recursos, proporciona contexto de seguridad y mucho más.

Sling Las API tienen la ventaja añadida de estar creadas para la extensión, lo que significa que a menudo es más fácil y seguro aumentar el comportamiento de las aplicaciones creadas mediante Sling API que las API de JCR menos ampliables.

Usos comunes de Sling API

API de JCR

La variable API de JCR (repositorio de contenido Java) 2.0 forma parte de una especificación para implementaciones JCR (en el caso de AEM, Apache Jackrabbit Oak). Toda la implementación de JCR debe cumplir e implementar estas API y, por lo tanto, es la API de nivel más bajo para interactuar con AEM contenido.

El propio JCR es un almacén de datos NoSQL basado en árboles y jerárquico que AEM utiliza como repositorio de contenido. El JCR tiene una amplia gama de API compatibles, que van desde el CRUD de contenido hasta la consulta de contenido. A pesar de esta API robusta, es raro que sean preferidos sobre los AEM de nivel superior y Sling abstracciones.

Siempre prefiera las API de JCR en lugar de las API de Apache Jackrabbit Oak. Las API de JCR están destinadas a interacción con un repositorio JCR, mientras que las API de Oak son para implementación un repositorio JCR.

Conceptos erróneos comunes sobre las API de JCR

Aunque el JCR es AEM repositorio de contenido, sus API NO son el método preferido para interactuar con el contenido. En su lugar, prefiera las API de AEM (página, recursos, etiqueta, etc.) o las API de recursos de Sling, ya que proporcionan mejores abstracciones.

PRECAUCIÓN

El uso generalizado de las interfaces de nodo y sesión de las API de JCR en una aplicación AEM es el olor del código. Asegúrese Sling Las API no deben usarse en su lugar.

Uso común de las API de JCR

API de OSGi

Hay poca superposición entre las API de OSGi y las API de nivel superior (AEM, Sling, y JCR), y la necesidad de utilizar las API de OSGi es poco frecuente y requiere un alto nivel de experiencia en desarrollo de AEM.

OSGi frente a las API de Apache Felix

OSGi define una especificación a la que todos los contenedores OSGi deben implementarse y ajustarse. AEM implementación OSGi, Apache Felix, también proporciona varias de sus propias API.

  • Preferir las API de OSGi (org.osgi) sobre las API de Apache Felix (org.apache.felix).

Uso común de las API de OSGi

Excepciones a la regla

Las siguientes son excepciones comunes a las reglas definidas anteriormente.

API de OSGi

Cuando se trata de abstracciones OSGi de bajo nivel, como definir o leer en propiedades de componentes OSGi, las abstracciones más recientes proporcionadas por org.osgi son preferibles a las absacciones de Sling de nivel superior. Las abstracciones de Sling de la competencia no se han marcado como @Deprecated y sugieran org.osgi alternativa.

Tenga en cuenta también que la definición del nodo de configuración OSGi prefiere cfg.json sobre el sling:OsgiConfig formato.

API de AEM Asset

  • Preferir com.day.cq.dam.api over com.adobe.granite.asset.api.

    • Mientras que la variable com.day.cq Las API de recursos proporcionan herramientas más gratuitas para casos prácticos AEM administración de recursos.
    • Las API de Granite Assets admiten casos de uso de administración de recursos de bajo nivel (versión, relaciones).

API de consulta

  • AEM QueryBuilder no admite determinadas funciones de consulta, como sugerencias, la revisión ortográfica y las sugerencias de índice, entre otras funciones menos comunes. Para consultar con estas funciones se prefiere JCR-SQL2.

Sling Registro de servlet

Sling Registro de filtros

Fragmentos de código útiles

Los siguientes son fragmentos útiles de código Java que ilustran las prácticas recomendadas para casos de uso comunes usando API discutidas. Estos fragmentos también ilustran cómo pasar de las API preferidas a las más preferidas.

Sesión de JCR a Sling ResourceResolver

Cerrar automáticamente ResourceResolver de Sling

Desde el AEM 6.2, la variable Sling ResourceResolver es AutoClosable en un try-with-resources instrucción. Con esta sintaxis, una llamada explícita a resourceResolver .close() no es necesario.

@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) { .. }

ResourceResolver de Sling cerrado manualmente

ResourceResolvers se puede cerrar manualmente en un finally , si no puede utilizarse la técnica de cierre automático que se muestra arriba.

@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(); }
}

Ruta de JCR a Sling Resource

Resource resource = ResourceResolver.getResource("/path/to/the/resource");

Nodo JCR a Sling Resource

Resource resource = resourceResolver.getResource(node.getPath());

Sling Resource a AEM recurso

Enfoque recomendado

DamUtil.resolveToAsset(..)resuelve cualquier recurso en el dam:Asset para acceder al objeto Asset , suba por el árbol según sea necesario.

Asset asset = DamUtil.resolveToAsset(resource);

Enfoque alternativo

La adaptación de un recurso a un recurso requiere que el recurso en sí sea la variable dam:Asset nodo .

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

Sling Recurso a AEM página

Enfoque recomendado

pageManager.getContainingPage(..) resuelve cualquier recurso en el cq:Page para acceder al objeto Página , suba por el árbol según sea necesario.

PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page page = pageManager.getContainingPage(resource);
Page page2 = pageManager.getContainingPage("/content/path/to/page/jcr:content/or/component");

Enfoque alternativo

La adaptación de un recurso a una página requiere que el propio recurso sea la cq:Page nodo .

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

Leer AEM propiedades de página

Utilice los captadores del objeto Página para obtener propiedades conocidas (getTitle(), getDescription(), etc.) y page.getProperties() para obtener el [cq:Page]/jcr:content ValueMap para recuperar otras propiedades.

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

Leer AEM propiedades de metadatos de recursos

La API de recursos proporciona métodos prácticos para leer propiedades desde el [dam:Asset]/jcr:content/metadata nodo . Tenga en cuenta que no se trata de un ValueMap, no se admite el segundo parámetro (valor predeterminado y conversión de tipo automático).

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

Lectura Sling Resource propiedades

Cuando las propiedades se almacenan en ubicaciones (propiedades o recursos relativos) en las que las API de AEM (página, recurso) no pueden acceder directamente, la variable Sling Se pueden utilizar Resources y ValueMaps para obtener los datos.

ValueMap properties = resource.getValueMap();
String value = properties.get("jcr:title", "Default title");
String relativeResourceValue = properties.get("relative/propertyName", "Default value");

En este caso, es posible que el objeto AEM tenga que convertirse en un Sling Resource para localizar de forma eficaz la propiedad o el subrecurso que desee.

AEM Página a Sling Resource

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

AEM recurso a Sling Resource

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

Escribir propiedades mediante Slings ModisibleValueMap

Uso Sling's MapaValorModificable para escribir propiedades en nodos. Esto solo puede escribir en el nodo inmediato (no se admiten las rutas de propiedad relativas).

Tenga en cuenta la llamada a .adaptTo(ModifiableValueMap.class) requiere permisos de escritura para el recurso; de lo contrario, devolverá un valor nulo.

ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);

properties.put("newPropertyName", "new value");
properties.put("propertyNameToUpdate", "updated value");
properties.remove("propertyToRemove");

resource.getResourceResolver().commit();

Crear una página AEM

Utilice siempre PageManager para crear páginas, ya que se necesita una plantilla de página, para definir e inicializar correctamente las páginas en 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(); }

Cree un Sling Recurso

ResourceResolver admite operaciones básicas para crear recursos. Al crear abstracciones de nivel superior (AEM páginas, recursos, etiquetas, etc.) utilice los métodos proporcionados por sus respectivos administradores.

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();

Eliminar un Sling Recurso

ResourceResolver admite la eliminación de un recurso. Al crear abstracciones de nivel superior (AEM páginas, recursos, etiquetas, etc.) utilice los métodos proporcionados por sus respectivos administradores.

resourceResolver.delete(resource);

resourceResolver.commit();

En esta página