Best Practices für Java-API

Adobe Experience Manager (AEM) basiert auf umfassender Open-Source-Software-Technologie, über die zahlreiche Java-APIs zur Verwendung während der Entwicklung bereitgestellt werden. In diesem Artikel werden die wichtigsten APIs sowie deren Verwendungszeitpunkt und -grund untersucht.

AEM basiert auf 4 primären Java-API-Sets.

  • Adobe Experience Manager (AEM)

    • Produktabstraktionen wie Seiten, Assets, Workflows usw.
  • Apache Sling Web Framework

    • REST- und ressourcenbasierte Abstraktionen wie Ressourcen, Wertzuordnungen und HTTP-Anforderungen.
  • JCR (Apache Jackrabbit Oak)

    • Daten- und Inhaltsabstraktionen wie Knoten, Eigenschaften und Sitzungen.
  • OSGi (Apache Felix)

    • OSGi-Programm-Container-Abstraktionen wie Services und (OSGi-) Komponenten.

Java-API-Voreinstellung "Faustregel"

Die allgemeine Regel besteht darin, die APIs/Abstraktionen in der folgenden Reihenfolge vorzuziehen:

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

Wenn eine API von AEM bereitgestellt wird, ziehen Sie sie vor Sling, JCR und OSGi. Wenn AEM keine API bereitstellt, bevorzugen Sie Sling über JCR und OSGi.

Diese Reihenfolge ist eine allgemeine Regel, d. h. es gibt Ausnahmen. Folgende Gründe können von dieser Regel abweichen:

  • Bekannte Ausnahmen, wie unten beschrieben.

  • In einer API auf höherer Ebene ist die erforderliche Funktionalität nicht verfügbar.

  • Die Verwendung im Kontext von vorhandenem Code (benutzerdefinierter oder AEM Produktcode), der selbst eine weniger bevorzugte API verwendet, und die Kosten für den Wechsel zur neuen API sind nicht zu rechtfertigen.

    • Es ist besser, die API der unteren Ebene konsistent zu verwenden, als eine Mischung zu erstellen.

AEM APIs

AEM APIs bieten Abstraktionen und Funktionen, die speziell für produktionsierte Anwendungsfälle gelten.

AEM PageManager und Seite APIs bieten Abstraktionen für cq:Page -Knoten in AEM, die Webseiten darstellen.

Diese Knoten sind über verfügbar. Sling APIs als Ressourcen und JCR-APIs als Knoten AEM APIs bieten Abstraktionen für gängige Anwendungsfälle. Durch die Verwendung der AEM-APIs wird ein konsistentes Verhalten zwischen AEM Produkt und den zu AEM Anpassungen und Erweiterungen sichergestellt.

com.adobe.* vs. com.day.* APIs

AEM APIs haben eine Präferenz für interne Pakete, die durch die folgenden Java-Pakete identifiziert wird, in der Reihenfolge ihrer Präferenz:

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

com.adobe.cq unterstützt Anwendungsfälle für Produkte. com.adobe.granite unterstützt produktübergreifende Anwendungsfälle wie Workflows oder Aufgaben (die produktübergreifend verwendet werden): AEM Assets, Sites usw.).

com.day.cq enthält "ursprüngliche"APIs. Diese APIs richten sich an zentrale Abstraktionen und Funktionen, die vor und/oder rund um den Erwerb von Day CQ. Diese APIs werden unterstützt und sollten nicht vermieden werden, es sei denn, com.adobe.cq oder com.adobe.granite eine (neuere) Alternative bereitstellen.

Neue Abstraktionen wie Content Fragments und Experience Fragments werden im com.adobe.cq Leerzeichen anstelle von com.day.cq weiter unten beschrieben.

Abfrage-APIs

AEM unterstützt mehrere Abfragesprachen. Die drei Hauptsprachen sind JCR-SQL2, XPath und AEM Query Builder.

Das wichtigste Anliegen ist die Beibehaltung einer konsistenten Abfragesprache in der gesamten Codebasis, um die Komplexität zu reduzieren und die Kosten für das Verständnis zu reduzieren.

Alle Abfragesprachen haben im Grunde dieselben Leistungsprofile wie Apache Oak überträgt sie für die endgültige Ausführung der Abfrage an JCR-SQL2, und die Konvertierungszeit an JCR-SQL2 ist im Vergleich zur Abfragezeit selbst vernachlässigbar.

Die bevorzugte API lautet AEM Query Builder, die Abstraktion auf höchster Ebene und eine robuste API zum Erstellen, Ausführen und Abrufen von Ergebnissen für Abfragen bereitstellt und Folgendes bereitstellt:

VORSICHT

AEM QueryBuilder-API leckt ein ResourceResolver-Objekt. Gehen Sie wie folgt vor, um dieses Leck zu vermeiden Codebeispiel.

Sling APIs

Apache Sling ist das RESTful-Web-Framework, das AEM unterstützt. Sling bietet HTTP-Anforderungsrouting, modelliert JCR-Knoten als Ressourcen, bietet Sicherheitskontext und vieles mehr.

Sling APIs bieten den zusätzlichen Vorteil, dass sie für Erweiterungen erstellt werden. Dies bedeutet, dass es häufig einfacher und sicherer ist, das Verhalten von Anwendungen zu erweitern, die mit Sling APIs als die weniger erweiterbaren JCR-APIs.

Häufige Verwendungen von Sling APIs

JCR-APIs

Die JCR (Java Content Repository) 2.0-APIs ist Teil einer Spezifikation für JCR-Implementierungen (im Falle von AEM, Apache Jackrabbit Oak). Alle JCR-Implementierungen müssen diesen APIs entsprechen und implementieren. Daher ist sie die niedrigste API für die Interaktion mit AEM Inhalt.

Das JCR selbst ist ein hierarchischer/baumbasierter NoSQL-Datenspeicher, der AEM als Content-Repository verwendet. Das JCR verfügt über eine Vielzahl unterstützter APIs, von Inhalts-CRUD bis hin zur Abfrage von Inhalten. Trotz dieser robusten API werden sie selten gegenüber der übergeordneten AEM bevorzugt. Sling Abstraktionen.

Bevorzugen Sie immer die JCR-APIs gegenüber den Apache Jackrabbit Oak-APIs. Die JCR-APIs sind für interagieren mit einem JCR-Repository verwenden, während die Oak-APIs für Umsetzung ein JCR-Repository.

Häufige falsche Vorstellungen über JCR-APIs

Während das JCR AEM Content Repository ist, sind seine APIs NICHT die bevorzugte Methode für die Interaktion mit dem Inhalt. Bevorzugen Sie stattdessen die AEM-APIs (Seite, Assets, Tag usw.) oder Sling Resource APIs , da sie bessere Abstraktionen bieten.

VORSICHT

Die breite Verwendung der Sitzungs- und Knotenschnittstellen von JCR-APIs in einer AEM Anwendung ist vom Code-Geruch abhängig. Sichern Sling APIs sollten nicht stattdessen verwendet werden.

Allgemeine Verwendung von JCR-APIs

OSGi-APIs

Es gibt kaum Überschneidungen zwischen den OSGi-APIs und den APIs auf höherer Ebene (AEM, Sling, und JCR) sowie die Notwendigkeit, OSGi-APIs zu verwenden, ist selten und erfordert ein hohes Maß an AEM Entwicklungskompetenz.

OSGi und Apache Felix-APIs

OSGi definiert eine Spezifikation, die alle OSGi-Container implementieren und erfüllen müssen. AEM OSGi-Implementierung stellt Apache Felix mehrere eigene APIs bereit.

  • Setzen Sie OSGi-APIs voran (org.osgi) über Apache Felix-APIs (org.apache.felix).

Allgemeine Verwendung von OSGi-APIs

Ausnahmen von der Regel

Im Folgenden finden Sie allgemeine Ausnahmen von den oben definierten Regeln.

OSGi-APIs

Bei der Behandlung von OSGi-Abstraktionen auf niedriger Ebene, z. B. beim Definieren oder Lesen in OSGi-Komponenteneigenschaften, werden die neueren Abstraktionen bereitgestellt von org.osgi werden gegenüber Sling-Abstraktionen auf höherer Ebene bevorzugt. Die konkurrierenden Sling-Abstraktionen wurden nicht als @Deprecated und empfiehlt org.osgi Alternative.

Beachten Sie außerdem, dass die Definition des OSGi-Konfigurationsknotens cfg.json über sling:OsgiConfig Format.

AEM Asset-APIs

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

    • Während com.day.cq Die Assets-APIs bieten umfassendere Tools für AEM Anwendungsfälle der Asset-Verwaltung.
    • Die Granite Assets-APIs unterstützen Anwendungsfälle für die Asset-Verwaltung auf niedriger Ebene (Version, Relationen).

Abfrage-APIs

  • AEM QueryBuilder unterstützt bestimmte Abfragefunktionen wie Empfehlungen, Rechtschreibprüfung und Indexhinweise unter anderen, weniger häufigen Funktionen. Für die Abfrage mit diesen Funktionen wird JCR-SQL2 bevorzugt.

Sling Servlet-Registrierung

Sling Registrierung filtern

Nützliche Codefragmente

Im Folgenden finden Sie hilfreiche Java-Codefragmente, die Best Practices für gängige Anwendungsfälle mit diskutierten APIs veranschaulichen. Diese Snippets zeigen auch, wie Sie von weniger bevorzugten APIs zu bevorzugten APIs wechseln können.

JCR-Sitzung an Sling ResourceResolver

Automatisches Schließen von Sling ResourceResolver

Seit AEM 6.2 wird die Sling ResourceResolver is AutoClosable in try-with-resources -Anweisung. Mithilfe dieser Syntax wird ein expliziter Aufruf an resourceResolver .close() nicht benötigt.

@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 manuell geschlossen

ResourceResolvers muss manuell in einem finally -Block, wenn die oben dargestellte Technik zum automatischen Schließen nicht verwendet werden kann.

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

JCR-Pfad zu Sling Resource

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

JCR-Knoten zu Sling Resource

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

Sling Resource zum AEM von Assets

Empfohlener Ansatz

DamUtil.resolveToAsset(..)löst alle Ressourcen unter dam:Asset zum Asset-Objekt hinzu, indem Sie nach Bedarf die Struktur nach oben navigieren.

Asset asset = DamUtil.resolveToAsset(resource);

Alternativansatz

Die Anpassung einer Ressource an ein Asset setzt voraus, dass die Ressource selbst die dam:Asset Knoten.

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

Sling Ressource auf AEM Seite

Empfohlener Ansatz

pageManager.getContainingPage(..) löst alle Ressourcen unter cq:Page in das Seitenobjekt ein, indem Sie nach Bedarf die Baumstruktur nach oben navigieren.

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

Alternativansatz

Die Anpassung einer Ressource an eine Seite setzt voraus, dass die Ressource selbst die cq:Page Knoten.

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

AEM Seiteneigenschaften lesen

Verwenden Sie die Getter des Seitenobjekts, um bekannte Eigenschaften zu erhalten (getTitle(), getDescription()usw.) und page.getProperties() um [cq:Page]/jcr:content ValueMap zum Abrufen anderer Eigenschaften.

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

Lesen AEM Asset-Metadateneigenschaften

Die Asset-API bietet praktische Methoden zum Lesen von Eigenschaften aus dem [dam:Asset]/jcr:content/metadata Knoten. Beachten Sie, dass dies keine ValueMap ist. Der zweite Parameter (Standardwert und automatische Umwandlung) wird nicht unterstützt.

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

Lesen Sling Resource properties

Wenn Eigenschaften an Orten (Eigenschaften oder relative Ressourcen) gespeichert werden, an denen die AEM-APIs (Seite, Asset) nicht direkt zugreifen können, wird die Sling Ressourcen und ValueMaps können zum Abrufen der Daten verwendet werden.

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

In diesem Fall muss das AEM-Objekt möglicherweise in eine Sling Resource , um die gewünschte Eigenschaft oder Unterressource effizient zu finden.

AEM Seite an Sling Resource

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

Asset AEM Sling Resource

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

Eigenschaften schreiben mit Slings ModifiableValueMap

Verwendung Slings ModifiableValueMap , um Eigenschaften in Knoten zu schreiben. Dies kann nur in den unmittelbaren Knoten schreiben (relative Eigenschaftspfade werden nicht unterstützt).

Notieren Sie den Aufruf von .adaptTo(ModifiableValueMap.class) erfordert Schreibberechtigungen für die Ressource, sonst wird null zurückgegeben.

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

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

resource.getResourceResolver().commit();

Erstellen einer AEM

Verwenden Sie PageManager immer, um Seiten zu erstellen, während eine Seitenvorlage benötigt wird. Dies ist erforderlich, um Seiten in AEM ordnungsgemäß zu definieren und zu initialisieren.

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

Erstellen Sie eine Sling Ressource

ResourceResolver unterstützt grundlegende Vorgänge zum Erstellen von Ressourcen. Beim Erstellen von Abstraktionen auf höherer Ebene (AEM Seiten, Assets, Tags usw.) die von den jeweiligen Managern bereitgestellten Methoden verwenden.

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

Löschen eines Sling Ressource

ResourceResolver unterstützt das Entfernen einer Ressource. Beim Erstellen von Abstraktionen auf höherer Ebene (AEM Seiten, Assets, Tags usw.) die von den jeweiligen Managern bereitgestellten Methoden verwenden.

resourceResolver.delete(resource);

resourceResolver.commit();

Auf dieser Seite