Adobe Experience Manager (AEM) repose sur une riche pile de logiciels open source qui expose de nombreuses API Java™ à utiliser lors du développement. Cet article explore les principales API et explique quand et pourquoi elles doivent être utilisées.
AEM est basé sur quatre Principaux ensembles d’API Java™.
Adobe Experience Manager (AEM)
Structure web Apache Sling
JCR (Apache Jackrabbit Oak)
OSGi (Apache Felix)
La règle générale est de 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 sur 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.
Les API d’AEM fournissent des abstractions et des fonctionnalités spécifiques aux cas d’utilisation productifs.
Par exemple, AEM PageManager et Page Les API fournissent des abstractions pour cq:Page
noeuds dans AEM représentant les pages web.
Bien que ces noeuds soient disponibles via Sling Les API 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 à .
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
Le com.adobe.cq
Le module prend en charge les cas d’utilisation de produits, alors 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.).
Le 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 par l’Adobe de Day CQ. Ces API sont prises en charge et doivent être évitées, sauf si com.adobe.cq
ou com.adobe.granite
Les packages ne fournissent PAS d’alternative (plus récente).
Nouvelles abstractions telles que Content Fragments et Experience Fragments sont conçus dans la variable com.adobe.cq
espace plutôt que com.day.cq
décrit ci-dessous.
AEM prend en charge plusieurs langages de requête. Les trois 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 possèdent effectivement les mêmes profils de performance, comme Apache Oak Les transpilotent vers JCR-SQL2 pour l’exécution de la requête finale, et le temps de conversion vers 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 constitue l’abstraction de niveau supérieur et fournit une API robuste pour la création, l’exécution et la récupération des résultats des 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)
Native API Java™ et API HTTP
AEM prédicats prise en charge des exigences de requête courantes
API extensible, permettant le développement de prédicats de requête
JCR-SQL2 et XPath peuvent être exécutés directement via Sling et API JCR, renvoi des résultats a Sling Ressources ou Noeuds JCR, respectivement.
AEM l’API QueryBuilder fuit un objet ResourceResolver. Pour atténuer cette fuite, procédez comme suit : exemple de code.
Apache Sling 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 de Sling API plutôt que les API JCR moins extensibles.
Accès aux noeuds JCR en tant que Sling Resources et accéder à leurs données via ValueMaps.
Fournir un contexte de sécurité via ResourceResolver.
Création et suppression de ressources via ResourceResolver méthodes create/move/copy/delete.
Mise à jour des propriétés via le ModifiableValueMap.
Création de blocs de création de traitement des demandes
Blocs de création de traitement de travail asynchrone
Le API JCR (Java™ Content Repository) 2.0 fait 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 à l’AEM de niveau supérieur et Sling abstractions.
Préférez toujours les API JCR aux API Apache Jackrabbit Oak. Les API JCR sont destinées à interaction avec un référentiel JCR, alors que les API Oak sont pour implémentation un référentiel 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 d’AEM (Page, Ressources, Balisage, etc.) ou les API de ressource Sling, car elles fournissent de meilleures abstractions.
L’utilisation étendue des interfaces Session et Node des API JCR dans une application AEM est une utilisation inodore du code. Assurez-vous que Sling Les API doivent être utilisées à la place.
Observation JCR (écoute des événements JCR)
Création de structures de noeuds profonds
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’expertise AEM développement.
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 code dynamique d’annulation/d’enregistrement des services/composants OSGi ;.
Vous trouverez ci-dessous des exceptions courantes aux règles définies ci-dessus.
Lorsque vous traitez d’abstractions OSGi de bas niveau, telles que la définition ou la lecture dans les propriétés de composant OSGi, les abstractions les plus récentes fournies par org.osgi
sont préférées aux abstractions Sling de niveau supérieur. Les abstractions Sling concurrentes n’ont pas été marquées comme @Deprecated
et suggérez le org.osgi
alternative.
Notez également que la définition de noeud de configuration OSGi préfère cfg.json
via sling:OsgiConfig
format.
Préférence com.day.cq.dam.api
over com.adobe.granite.asset.api
.
com.day.cq
Les API Assets offrent des outils plus complets pour AEM cas d’utilisation de la gestion des ressources.@SlingServlet
@SlingFilter
Vous trouverez ci-dessous des extraits de code Java™ qui illustrent les bonnes pratiques relatives aux 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.
Depuis AEM 6.2, la variable Sling ResourceResolver est AutoClosable
dans 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 une finally
block, 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(); }
}
Resource resource = ResourceResolver.getResource("/path/to/the/resource");
Resource resource = resourceResolver.getResource(node.getPath());
Le DamUtil.resolveToAsset(..)
résout n’importe quelle ressource sous la fonction dam:Asset
à l’objet Asset en montant l’arborescence selon les besoins.
Asset asset = DamUtil.resolveToAsset(resource);
L’adaptation d’une ressource à une ressource nécessite que la ressource elle-même soit la dam:Asset
noeud .
Asset asset = resource.adaptTo(Asset.class);
pageManager.getContainingPage(..)
résout toute ressource sous la propriété cq:Page
à l’objet 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");
L’adaptation d’une ressource à une page requiert que la ressource elle-même soit la cq:Page
noeud .
Page page = resource.adaptTo(Page.class);
Utilisez les getters de l’objet Page pour obtenir des propriétés connues (getTitle()
, getDescription()
, etc.) et page.getProperties()
pour obtenir la variable [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 [dam:Asset]/jcr:content/metadata
noeud . Il ne s’agit pas d’une ValueMap, le deuxiè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 les propriétés sont stockées dans des emplacements (propriétés ou ressources relatives) auxquels les API AEM (Page, Ressource) ne peuvent pas accéder directement, la variable Sling Les ressources et les ValueMaps peuvent être utilisés 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.
Resource resource = page.adaptTo(Resource.class);
Resource resource = asset.adaptTo(Resource.class);
Utilisation Sling's 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 l’appel à .adaptTo(ModifiableValueMap.class)
nécessite des autorisations d’écriture sur la ressource, sinon elle renvoie 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, 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(); }
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 (Pages d’AEM, Ressources, Balises, etc.), utilisez 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 (Pages d’AEM, Ressources, Balises, etc.), utilisez les méthodes fournies par leurs gestionnaires respectifs.
resourceResolver.delete(resource);
resourceResolver.commit();