Bonnes pratiques relatives aux API Java

Adobe Experience Manager (AEM) repose sur une riche pile de logiciels open source qui expose de nombreuses API Java à utiliser pendant le développement. Cet article explore les principales API et explique quand et pourquoi elles doivent être utilisées.

AEM est basé sur 4 ensembles d’API Java Principaux.

  • Adobe Experience Manager (AEM)

    • abstractions de produits telles que pages, ressources, workflows, etc.
  • Structure web Apache Sling

    • abstractions REST et basées sur des ressources telles que les ressources, les mappages de valeurs et les requêtes HTTP.
  • JCR (Apache Jackrabbit Oak)

    • Extraits de données et de contenu tels que le noeud, les propriétés et les sessions.
  • OSGi (Apache Felix)

    • abstractions du conteneur d’applications OSGi telles que les composants de services et (OSGi).

Préférence API Java "règle de base"

La règle générale est de préférer les API/abstractions dans l’ordre suivant :

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

Si une API est fournie par AEM, préférez-la à Sling, JCR et OSGi. Si AEM ne fournit pas d’API, préférez Sling à JCR et OSGi.

Cet ordre est une règle générale, ce qui signifie qu'il existe des exceptions. Les raisons possibles de rompre avec cette règle sont les suivantes :

  • Exceptions connues, comme décrit ci-dessous.

  • La fonctionnalité requise n’est pas disponible dans une API de niveau supérieur.

  • Fonctionner dans le contexte du code existant (code de produit personnalisé ou AEM) qui utilise lui-même une API moins prisée, et le coût de déplacement vers la nouvelle API est injustifiable.

    • Il est préférable d’utiliser systématiquement l’API de niveau inférieur plutôt que de créer un mélange.

API AEM

Les API d’AEM fournissent des abstractions et des fonctionnalités spécifiques aux cas d’utilisation productifs.

Par exemple, AEM API PageManager et Page fournissent des abstractions pour les noeuds cq:Page dans AEM qui représentent des pages web.

Bien que ces noeuds soient disponibles via les API Sling en tant que ressources et les API JCR en tant que noeuds, les API AEM fournissent des abstractions pour les cas d’utilisation courants. L’utilisation des API d’AEM permet d’assurer un comportement cohérent entre AEM le produit, ainsi que des personnalisations et des extensions à .

com.adobe.* par rapport à com.day.* API

AEM API ont une préférence intra-package, identifiée par les packages Java suivants, par ordre de préférence :

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

com.adobe.cq prend en charge les cas d’utilisation de produits, tandis que com.adobe.granite prend en charge les cas d’utilisation de plateformes inter-produits, tels que les workflows ou les tâches (qui sont utilisés dans plusieurs produits : AEM Assets, Sites, etc.).

com.day.cq contient des API "originales". Ces API traitent des abstractions et fonctionnalités de base qui existaient avant et/ou autour de l’acquisition de Day CQ par l’Adobe. Ces API sont prises en charge et ne doivent pas être évitées, sauf si com.adobe.cq ou com.adobe.granite fournissent une alternative (plus récente).

De nouvelles abstractions telles que Content Fragments et Experience Fragments sont construites dans l’espace com.adobe.cq au lieu de com.day.cq décrit ci-dessous.

API de requête

AEM prend en charge plusieurs langages de requête. Les 3 langues principales sont JCR-SQL2, XPath et AEM Query Builder.

La préoccupation la plus importante est de conserver un langage de requête cohérent dans l’ensemble de la base de code, afin de réduire la complexité et les coûts à comprendre.

Tous les langages de requête ont effectivement les mêmes profils de performances, car Apache Oak les transpiles en JCR-SQL2 pour l’exécution de la requête finale, et le temps de conversion en JCR-SQL2 est négligeable par rapport au temps de requête lui-même.

L’API préférée est AEM Query Builder, qui est l’abstraction de niveau supérieur et fournit une API robuste pour créer, exécuter et récupérer les résultats des requêtes. Elle fournit les éléments suivants :

  • Construction de requêtes simple et paramétrée (paramètres de requête modélisés en tant que carte)

  • API Java et API HTTP natives

  • AEM Query Debugger

  • AEM prédicats prenant en charge les exigences de requête courantes

  • API extensible, permettant le développement de prédicats de requête personnalisés

  • Les API JCR-SQL2 et XPath peuvent être exécutées directement via Sling et JCR, renvoyant respectivement les résultats des noeuds Sling Resources ou JCR.

ATTENTION

AEM l’API QueryBuilder fuit un objet ResourceResolver. Pour atténuer cette fuite, suivez cet exemple de code.

Slingles API ;

Sling Apache est la structure web RESTful qui sous-tend AEM. Sling fournit le routage des requêtes HTTP, modélise les noeuds JCR en tant que ressources, fournit un contexte de sécurité, etc.

Sling Les API ont l’avantage supplémentaire d’être créées pour l’extension, ce qui signifie qu’il est souvent plus facile et plus sûr d’augmenter le comportement des applications créées à l’aide d’ Sling API que les API JCR moins extensibles.

Utilisations courantes des API Sling

API JCR

Les API JCR (Java Content Repository) 2.0 font partie d’une spécification pour les implémentations JCR (dans le cas d’AEM, Apache Jackrabbit Oak). Toute implémentation JCR doit se conformer à ces API et les mettre en oeuvre. Il s’agit donc de l’API de niveau le plus bas pour interagir avec le contenu AEM.

Le JCR lui-même est une AEM de banque de données NoSQL hiérarchique/basée sur une arborescence qui utilise comme référentiel de contenu. Le JCR dispose d’une vaste gamme d’API prises en charge, allant du CRUD de contenu à l’interrogation de contenu. Malgré cette API robuste, il est rare qu’elles soient préférées aux AEM de niveau supérieur et aux abstractions Sling.

Préférez toujours les API JCR aux API Apache Jackrabbit Oak. Les API JCR servent à interagir avec un référentiel JCR, tandis que les API Oak servent à implémenter un référentiel JCR.

Erreurs courantes à propos des API JCR

Bien que JCR soit AEM référentiel de contenu, ses API ne sont PAS la méthode préférée pour interagir avec le contenu. À la place, préférez les API AEM (Page, Ressources, Balise, etc.) ou des API de ressources Sling, car elles fournissent de meilleures abstractions.

ATTENTION

L’utilisation généralisée des interfaces Session et Node des API JCR dans une application AEM est une utilisation puissante du code. Assurez-vous que les API Sling ne doivent pas être utilisées à la place.

Utilisations courantes des API JCR

API OSGi

Il existe peu de chevauchement entre les API OSGi et les API de niveau supérieur (AEM, Sling et JCR), et la nécessité d’utiliser les API OSGi est rare et nécessite un haut niveau d’AEM expertise en développement.

API OSGi et Apache Felix

OSGi définit une spécification que tous les conteneurs OSGi doivent implémenter et respecter. AEM mise en oeuvre OSGi, Apache Felix, fournit également plusieurs de ses propres API.

  • Préférez les API OSGi (org.osgi) par rapport aux API Apache Felix (org.apache.felix).

Utilisations courantes des API OSGi

  • Annotations OSGi pour la déclaration des services et composants OSGi.

  • API OSGi pour l’annulation/l’enregistrement dynamique des services/composants OSGi dans le code OSGi.

    • Préférez l’utilisation des annotations OSGi DS 1.2 lorsque la gestion conditionnelle des services/composants OSGi n’est pas nécessaire (ce qui est le plus souvent le cas).

Exceptions à la règle

Vous trouverez ci-dessous des exceptions courantes aux règles définies ci-dessus.

AEM API Asset

  • Préférez com.day.cq.dam.api par com.adobe.granite.asset.api.

    • Bien que les API Assets com.day.cq fournissent des outils supplémentaires pour les cas d’utilisation de la gestion des ressources AEM.
    • Les API de ressources Granite prennent en charge les cas d’utilisation de la gestion des ressources de bas niveau (version, relations).

API de requête

  • AEM QueryBuilder ne prend pas en charge certaines fonctions de requête telles que suggestions, les indices de vérification orthographique et d’index parmi d’autres fonctions moins courantes. Il est préférable d’effectuer des requêtes avec ces fonctions JCR-SQL2.

Sling Enregistrement de servlet

  • Sling enregistrement de servlet, préférez les annotations OSGi DS 1.2 avec @ SlingServletResourceTypesover @SlingServlet

Sling Enregistrement de filtre

  • Sling enregistrement de filtre, préférez les annotations OSGi DS 1.2 avec @ SlingServletFilterover @SlingFilter

Fragments de code utiles

Vous trouverez ci-dessous des fragments de code Java utiles qui illustrent les bonnes pratiques pour les cas d’utilisation courants à l’aide des API discutées. Ces fragments illustrent également comment passer d’API moins prisées à des API plus préférées.

Session JCR à Sling ResourceResolver

Sling ResourceResolver à fermeture automatique

Depuis AEM 6.2, le ResourceResolver est AutoClosable dans une instruction try-with-resources. Sling En utilisant cette syntaxe, un appel explicite à resourceResolver .close() n’est pas nécessaire.

@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 fermé manuellement

ResourceResolvers peut être fermé manuellement dans un bloc finally si la technique de fermeture automatique illustrée ci-dessus ne peut pas être utilisée.

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

Chemin d’accès JCR à Sling Resource

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

Noeud JCR à Sling Resource

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

Sling Resource pour AEM la ressource

Approche recommandée

DamUtil.resolveToAsset(..)résout toute ressource sous l’objet dam:Asset de ressource en montant l’arborescence selon les besoins.

Asset asset = DamUtil.resolveToAsset(resource);

Approche alternative

L’adaptation d’une ressource à une ressource nécessite que la ressource elle-même soit le noeud dam:Asset.

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

Sling Ressource vers AEM page

Approche recommandée

pageManager.getContainingPage(..) résout toute ressource sous l’objet cq:Page de page en montant l’arborescence selon les besoins.

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

Approche alternative

Pour adapter une ressource à une page, la ressource elle-même doit être le noeud cq:Page.

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

Lire les propriétés AEM page

Utilisez les getters de l’objet Page pour obtenir des propriétés bien connues (getTitle(), getDescription(), etc.) et page.getProperties() pour obtenir la [cq:Page]/jcr:content ValueMap afin de récupérer d’autres propriétés.

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

Lecture des propriétés AEM métadonnées des ressources

L’API Asset fournit des méthodes pratiques pour lire les propriétés à partir du noeud [dam:Asset]/jcr:content/metadata. Notez qu’il ne s’agit pas d’une ValueMap, le 2e paramètre (valeur par défaut et diffusion de type automatique) n’est pas pris en charge.

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

Lire les Sling Resource propriétés

Lorsque les propriétés sont stockées dans des emplacements (propriétés ou ressources relatives) auxquels les API AEM (Page, Asset) ne peuvent pas accéder directement, les ressources Sling et les ValueMaps peuvent être utilisées pour obtenir les données.

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

Dans ce cas, il se peut que l’objet AEM doive être converti en Sling Resource pour localiser efficacement la propriété ou la sous-ressource souhaitée.

AEM Page à Sling Resource

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

AEM Ressource à Sling Resource

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

Écrire des propriétés à l’aide de Sling's ModifiableValueMap

Utilisez Sling de ModifiableValueMap pour écrire des propriétés sur des noeuds. Cela peut uniquement écrire sur le noeud immédiat (les chemins de propriété relatifs ne sont pas pris en charge).

Notez que l’appel à .adaptTo(ModifiableValueMap.class) nécessite des autorisations d’écriture sur la ressource, sinon il renverra null.

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

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

resource.getResourceResolver().commit();

Création d’une page AEM

Utilisez toujours PageManager pour créer des pages, car un modèle de page est nécessaire pour définir et initialiser correctement les pages dans 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(); }

Créer une ressource Sling

ResourceResolver prend en charge les opérations de base pour la création de ressources. Lors de la création d’abstractions de niveau supérieur (AEM Pages, Ressources, Balises, etc.) utiliser les méthodes fournies par leurs responsables respectifs.

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

Suppression d’une ressource Sling

ResourceResolver prend en charge la suppression d’une ressource. Lors de la création d’abstractions de niveau supérieur (AEM Pages, Ressources, Balises, etc.) utiliser les méthodes fournies par leurs responsables respectifs.

resourceResolver.delete(resource);

resourceResolver.commit();

Sur cette page