Adobe Experience Manager (AEM) est construit sur une riche pile de logiciels open source qui expose de nombreuses API Java à des fins de développement. Cet article explore les principales API et explique quand et pourquoi elles doivent être utilisées.
aem est basé sur 4 jeux d'API Java Principaux.
Adobe Experience Manager (AEM)
Apache SlingWeb Framework
JCR (Apache Jackrabbit Oak)
OSGi (Apache Felix)
La règle générale consiste à préférer les API/abstractions dans l’ordre suivant :
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 au JCR et OSGi.
Cet ordre est une règle générale, ce qui signifie qu'il existe des exceptions. Les raisons acceptables pour rompre avec cette règle sont les suivantes :
Exceptions bien 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.
Les API AEM fournissent des abstractions et des fonctionnalités spécifiques aux cas d’utilisation produits.
Par exemple, les API AEM 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 AEM permet d’assurer un comportement cohérent entre AEM le produit, ainsi que des personnalisations et des extensions pour les AEM.
aem API ont une préférence intra-package, identifiée par les packages Java suivants, par ordre de préférence :
com.adobe.cq
com.adobe.granite
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 processus ou les tâches (qui sont utilisés entre les produits : AEM Assets, Sites, etc.).
com.day.cq
contient des API "d’origine". Ces API traitent des abstractions et fonctionnalités de base qui existaient avant et/ou autour de l'acquisition par le Adobe de [!DNL Day CQ]. Ces API sont prises en charge et ne doivent pas être évitées, à moins que com.adobe.cq
ou com.adobe.granite
ne fournissent une alternative (plus récente).
De nouvelles abstractions telles que Content Fragments et Experience Fragments sont construites dans l'espace com.adobe.cq
plutôt que com.day.cq
décrit ci-dessous.
aem prend en charge plusieurs langues de requête. Les trois langues principales sont JCR-SQL2, XPath et AEM Requête Builder.
Le plus important est de maintenir un langage de requête cohérent dans toute la base de code, afin de réduire la complexité et les coûts de compréhension.
Tous les langages de requête ont effectivement les mêmes profils de performance, car Apache Oak les transpile en JCR-SQL2 pour l'exécution finale de la requête, 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 Requête Builder, qui est l’abstraction de niveau supérieur et fournit une API robuste pour construire, exécuter et récupérer les résultats pour les requêtes, et 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)
Prévisions d'OOTB prenant en charge les besoins de requête communs
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 par Sling et JCR, renvoyant respectivement les résultats suivants : Sling Resources ou Noeuds JCR.
aem l'API QueryBuilder fuit un objet ResourceResolver. Pour atténuer cette fuite, suivez cet exemple de code.
Sling Apacheis est le cadre web RESTful qui sous-tend AEM. Sling fournit un routage de requête HTTP, modélise les noeuds JCR en tant que ressources, fournit un contexte de sécurité, et bien plus encore.
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.
Accès aux noeuds JCR sous la forme Sling Resources et accès à leurs données via ValueMaps.
Fournir un contexte de sécurité via ResourceResolver.
Création et suppression de ressources via les méthodes de création/déplacement/copie/suppression de ResourceResolver.
Mise à jour des propriétés via ModifiableValueMap.
Création de blocs de création de traitement de demande
Blocs de création de traitement de travail asynchrones
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). Toutes les implémentations JCR doivent se conformer à ces API et les implémenter. Il s’agit donc de l’API de niveau le plus bas pour interagir avec le contenu AEM.
Le JCR lui-même est un AEM de banque de données NoSQL hiérarchisé/basé sur une arborescence utilisé comme référentiel de contenu. Le JCR dispose d’une vaste gamme d’API prises en charge, allant du contenu CRUD à l’interrogation de contenu. Malgré cette API robuste, il est rare qu'elles soient préférées à l'AEM de niveau supérieur et aux abstractions Sling.
Préférez toujours les API JCR plutôt que les API Apache Jackrabbit Oak. Les API JCR sont destinées à interagir avec un référentiel JCR, tandis que les API Oak sont destinées à implémenter un référentiel JCR.
Bien que le 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. Préférez plutôt les API AEM (Page, Ressources, Balise, etc.) ou les API de ressources Sling car elles fournissent de meilleures abstractions.
L’utilisation généralisée des interfaces Session et Noeud des API JCR dans une application AEM est à l’odorat du code. Assurez-vous que les API Sling ne doivent pas être utilisées à la place.
Observation JCR (écoute des événements JCR)
Création de structures de noeud profondes
Il y a 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'expertise en développement AEM.
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.
org.osgi
) sur les API Apache Felix (org.apache.felix
).Annotations OSGi pour la déclaration des services et composants OSGi.
API OSGi pour les un/l'enregistrement dynamique des services/composants OSGi dans le code.
Voici quelques exceptions courantes aux règles définies ci-dessus.
Préférez com.day.cq.dam.api
par com.adobe.granite.asset.api
.
com.day.cq
API Ressources offrent davantage d'outils complémentaires aux cas d'utilisation de la gestion des ressources AEM.@SlingServlet
@SlingFilter
Les extraits de code Java suivants illustrent les meilleures pratiques relatives aux cas d’utilisation courants à l’aide des API décrites. Ces extraits illustrent également comment passer d’API moins préférées à des API plus préférées.
Depuis AEM 6.2, le ResourceResolver Sling est AutoClosable
dans une instruction try-with-resources. 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) { .. }
ResourceResolvers peut être fermé manuellement dans un bloc finally
si la technique de fermeture automatique décrite 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(); }
}
Resource resource = ResourceResolver.getResource("/path/to/the/resource");
Resource resource = resourceResolver.getResource(node.getPath());
DamUtil.resolveToAsset(..)
résout toute ressource sous l'objet dam:Asset
d'actif en montant l'arborescence si nécessaire.
Asset asset = DamUtil.resolveToAsset(resource);
L'adaptation d'une ressource à un actif requiert que la ressource elle-même soit le noeud dam:Asset
.
Asset asset = resource.adaptTo(Asset.class);
pageManager.getContainingPage(..)
résout toute ressource sous l'objet Page cq:Page
en montant l'arborescence si nécessaire.
PageManager pageManager = resourceResolver.adaptTo(PageManager.class);
Page page = pageManager.getContainingPage(resource);
Page page2 = pageManager.getContainingPage("/content/path/to/page/jcr:content/or/component");
L'adaptation d'une ressource à une page requiert que la ressource elle-même soit le noeud cq:Page
.
Page page = resource.adaptTo(Page.class);
Utilisez les méthodes getters de l'objet Page pour obtenir des propriétés bien connues (getTitle()
, getDescription()
, etc.) et page.getProperties()
pour obtenir le [cq:Page]/jcr:content
ValueMap pour 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());
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’un ValueMap, le 2ème paramètre (valeur par défaut et casting 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");
Lorsque des 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 zones 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, l'objet AEM peut être converti en Sling Resource pour localiser efficacement la propriété ou la sous-ressource souhaitée.
Resource resource = page.adaptTo(Resource.class);
Resource resource = asset.adaptTo(Resource.class);
Utilisez Sling de ModifiableValueMap pour écrire des propriétés sur les noeuds. Ceci ne peut écrire que 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 retournera null.
ModifiableValueMap properties = resource.adaptTo(ModifiableValueMap.class);
properties.put("newPropertyName", "new value");
properties.put("propertyNameToUpdate", "updated value");
properties.remove("propertyToRemove");
resource.getResourceResolver().commit();
Utilisez toujours PageManager pour créer des pages au fur et à mesure qu'il utilise 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(); }
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 gestionnaires 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();
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 gestionnaires respectifs.
resourceResolver.delete(resource);
resourceResolver.commit();