Comprendere le best practice per le API Java

Adobe Experience Manager (AEM) è basato su uno stack software open-source ricco che espone molte API Java da utilizzare durante lo sviluppo. Questo articolo esplora le API principali e spiega quando e perché dovrebbero essere utilizzate.

AEM è basato su 4 set di API Java principali.

  • Adobe Experience Manager (AEM)

    • astrazioni di prodotto come pagine, risorse, flussi di lavoro, ecc.
  • Apache SlingFramework Web

    • astrazioni REST e basate su risorse come risorse, mappe dei valori e richieste HTTP.
  • JCR (Apache Jackrabbit Oak)

    • astrazioni di dati e contenuti quali nodo, proprietà e sessioni.
  • OSGi (Apache Felix)

    • astrazioni del contenitore dell'applicazione OSGi quali servizi e componenti (OSGi).

Preferenza API Java "regola del pollice"

La regola generale è di preferire le API/astrazioni nel seguente ordine:

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

Se AEM fornisce un’API, preferiscila rispetto a Sling, JCR e OSGi. Se AEM non fornisce un’API, preferisci Sling rispetto a JCR e OSGi.

Questo ordine è una regola generale, il che significa che esistono delle eccezioni. Motivi accettabili per uscire da questa regola sono i seguenti:

  • Eccezioni ben note, come descritto di seguito.

  • La funzionalità richiesta non è disponibile in un’API di livello superiore.

  • Operando nel contesto del codice esistente (codice di prodotto personalizzato o AEM) che utilizza essa stessa un’API meno preferita e il costo per passare alla nuova API è ingiustificabile.

    • È meglio utilizzare in modo coerente l’API di livello inferiore rispetto a creare un mix.

API di AEM

Le API di AEM forniscono astrazioni e funzionalità specifiche per i casi d’uso prodotti.

Ad esempio, le API di AEM PageManager e Page forniscono astrazioni per i nodi cq:Page in AEM che rappresentano pagine web.

Anche se questi nodi sono disponibili tramite Sling API as Resources (Risorse) e API JCR as Nodes (Nodi), le API di AEM forniscono astrazioni per i casi d’uso comuni. L’utilizzo delle API AEM assicura un comportamento coerente tra AEM e il prodotto, nonché personalizzazioni ed estensioni per AEM.

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

Le API AEM hanno una preferenza intra-pacchetto, identificata dai seguenti pacchetti Java, in ordine di preferenza:

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

com.adobe.cq supporta i casi di utilizzo dei prodotti, mentre com.adobe.granite supporta i casi di utilizzo di piattaforme cross-product, come i flussi di lavoro o le attività (utilizzati tra i prodotti: AEM Assets, Sites, ecc.).

com.day.cq contiene API "originali". Queste API riguardano le astrazioni e le funzionalità principali che esistevano prima e/o intorno all'acquisizione di [!DNL Day CQ] da parte di Adobe. Queste API sono supportate e non devono essere evitate, a meno che com.adobe.cq o com.adobe.granite non forniscano un'alternativa (più recente).

Le nuove astrazioni come Content Fragments e Experience Fragments sono integrate nello spazio com.adobe.cq anziché com.day.cq come descritto di seguito.

API di query

AEM supporta più linguaggi di query. Le tre lingue principali sono JCR-SQL2, XPath e AEM Query Builder.

La preoccupazione più importante è mantenere un linguaggio di query coerente all'interno della base di codice, per ridurre la complessità e i costi da comprendere.

Tutti i linguaggi di query hanno effettivamente gli stessi profili di prestazioni, in quanto Apache Oak li trasferisce a JCR-SQL2 per l'esecuzione finale della query, e il tempo di conversione a JCR-SQL2 è trascurabile rispetto al tempo di query stesso.

L’API preferita è AEM Query Builder, che è l’astrazione di livello più alto e fornisce un’API affidabile per la costruzione, l’esecuzione e il recupero dei risultati per le query, e fornisce quanto segue:

ATTENZIONE

L'API di AEM QueryBuilder perde un oggetto ResourceResolver. Per attenuare questa perdita, segui questo esempio di codice.

Sling API

Sling Apacheè il framework web RESTful che supporta AEM. Sling fornisce routing delle richieste HTTP, modelli di nodi JCR come risorse, fornisce contesto di sicurezza e molto altro.

Sling Le API hanno il vantaggio aggiuntivo di essere create per l’estensione, il che significa che spesso è più facile e sicuro migliorare il comportamento delle applicazioni create utilizzando Sling le API rispetto alle API JCR meno estensibili.

Utilizzo comune delle API Sling

API JCR

Le API JCR (Java Content Repository) 2.0 fanno parte di una specifica per le implementazioni JCR (nel caso di AEM, Apache Jackrabbit Oak). Tutte le implementazioni JCR devono essere conformi a queste API e implementarle; pertanto, è l’API di livello più basso per interagire con i contenuti di AEM.

Il JCR stesso è un datastore NoSQL gerarchico/basato su albero utilizzato da AEM come archivio dei contenuti. Il JCR dispone di una vasta gamma di API supportate, che vanno dal CRUD del contenuto alla query del contenuto. Nonostante questa solida API, è raro che siano preferite rispetto alle astrazioni di livello più alto di AEM e Sling .

Preferisci sempre le API JCR rispetto alle API Apache Jackrabbit Oak. Le API JCR sono per interagire con un archivio JCR, mentre le API Oak sono per implementare un archivio JCR.

Concetti sbagliati comuni sulle API JCR

Mentre JCR è l’archivio dei contenuti di AEM, le sue API NON sono il metodo preferito per interagire con il contenuto. Preferisce invece le API AEM (Pagina, Risorse, Tag, ecc.) o API di risorse Sling in quanto forniscono migliori astrazioni.

ATTENZIONE

L'ampio utilizzo delle interfacce Session e Node delle API JCR in un'applicazione AEM è un odore di codice. Assicurati che le API Sling non siano utilizzate al loro posto.

Utilizzo comune delle API JCR

API OSGi

C'è poca sovrapposizione tra le API OSGi e le API di livello superiore (AEM, Sling e JCR), e la necessità di utilizzare le API OSGi è rara e richiede un alto livello di esperienza di sviluppo AEM.

API OSGi e Apache Felix

OSGi definisce una specifica a cui tutti i contenitori OSGi devono implementare e conformarsi. L’implementazione OSGi di AEM, Apache Felix, fornisce anche diverse delle proprie API.

  • Preferisci le API OSGi (org.osgi) rispetto alle API Apache Felix (org.apache.felix).

Utilizzo comune delle API OSGi

  • Annotazioni OSGi per dichiarare i servizi e i componenti OSGi.

  • API OSGi per l'annullamento/registrazione dinamica dei servizi/componenti OSGi🔗 in-code.

    • Preferisci l’utilizzo di annotazioni OSGi DS 1.2 quando non è necessaria la gestione condizionale del servizio/componente OSGi (cosa che si verifica più spesso).

Eccezioni alla regola

Di seguito sono riportate alcune eccezioni comuni alle regole definite in precedenza.

API di AEM Asset

  • Preferisci com.day.cq.dam.api su com.adobe.granite.asset.api.

    • Le API di com.day.cq Assets forniscono strumenti più gratuiti ai casi d’uso di AEM per la gestione delle risorse.
    • Le API di Granite Assets supportano casi d’uso per la gestione delle risorse di basso livello (versione, relazioni).

API di query

  • AEM QueryBuilder non supporta alcune funzioni di query come suggerimenti, controllo ortografia e suggerimenti di indice, tra le altre funzioni meno comuni. Per eseguire query con queste funzioni è preferibile JCR-SQL2.

Sling Registrazione servlet

  • Sling Registrazione servlet, preferisci le annotazioni OSGi DS 1.2 con @ SlingServletResourceTypesover @SlingServlet

Sling Registrazione del filtro

  • Sling registrazione del filtro, preferisci le annotazioni OSGi DS 1.2 con @ SlingServletFilterover @SlingFilter

Frammenti di codice utili

Di seguito sono riportati utili snippet di codice Java che illustrano le best practice per i casi d’uso comuni che utilizzano API discusse. Questi snippet illustrano anche come passare da API meno preferite a API più preferite.

Sessione JCR in Sling ResourceResolver

Chiusura automatica di Sling ResourceResolver

A partire da AEM 6.2, il Sling ResourceResolver è AutoClosable in un'istruzione try-with-resources . Utilizzando questa sintassi, non è necessaria una chiamata esplicita a resourceResolver .close() .

@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 chiuso manualmente

È possibile chiudere manualmente i ResourceResolver in un blocco finally se non è possibile utilizzare la tecnica di chiusura automatica mostrata sopra.

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

Percorso JCR a Sling Resource

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

Nodo JCR su Sling Resource

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

Sling Resource a AEM Assets

Approccio consigliato

DamUtil.resolveToAsset(..)risolve tutte le risorse sotto dam:Asset all’oggetto Risorsa spostandosi verso l’alto nella struttura, in base alle esigenze.

Asset asset = DamUtil.resolveToAsset(resource);

Approccio alternativo

Per adattare una risorsa a una risorsa è necessario che la stessa sia il nodo dam:Asset.

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

Sling Pagina Risorsa ad AEM

Approccio consigliato

pageManager.getContainingPage(..) risolve tutte le risorse sotto cq:Page all’oggetto Page spostandosi verso l’alto nella struttura, in base alle esigenze.

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

Approccio alternativo

Per adattare una risorsa a una pagina è necessario che la risorsa stessa sia il nodo cq:Page .

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

Proprietà pagina AEM

Utilizzare i getters dell'oggetto Page per ottenere proprietà ben note (getTitle(), getDescription(), ecc.) e page.getProperties() per ottenere il valore [cq:Page]/jcr:content ValueMap per il recupero di altre proprietà.

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

Proprietà dei metadati di AEM Asset

L’API delle risorse fornisce metodi pratici per leggere le proprietà dal nodo [dam:Asset]/jcr:content/metadata . Nota che non si tratta di un ValueMap, il secondo parametro (valore predefinito e casting automatico) non è supportato.

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

Proprietà Sling Resource

Quando le proprietà sono memorizzate in posizioni (proprietà o risorse relative) a cui le API AEM (Pagina, Risorsa) non possono accedere direttamente, per ottenere i dati è possibile utilizzare le Sling Risorse e ValueMaps .

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

In questo caso, potrebbe essere necessario convertire l’oggetto AEM in un Sling Resource per individuare in modo efficiente la proprietà o la risorsa secondaria desiderata.

Pagina AEM su Sling Resource

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

AEM Asset in Sling Resource

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

Proprietà di scrittura utilizzando la proprietà ModifiableValueMap di Sling

Utilizza Sling di ModificableValueMap per scrivere le proprietà sui nodi. Questo può solo scrivere sul nodo immediato (i percorsi delle proprietà relative non sono supportati).

Nota che la chiamata a .adaptTo(ModifiableValueMap.class) richiede autorizzazioni di scrittura per la risorsa, altrimenti restituisce null.

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

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

resource.getResourceResolver().commit();

Creare una pagina AEM

Utilizza sempre PageManager per creare le pagine in quanto richiede un modello di pagina, è necessario per definire e inizializzare correttamente le pagine in 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(); }

Creare una risorsa Sling

ResourceResolver supporta operazioni di base per la creazione di risorse. Durante la creazione di astrazioni di livello superiore (pagine AEM, risorse, tag, ecc.) utilizzare i metodi forniti dai rispettivi responsabili.

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

Eliminare una risorsa Sling

ResourceResolver supporta la rimozione di una risorsa. Quando crei astrazioni di livello superiore (pagine AEM, risorse, tag, ecc.) utilizzare i metodi forniti dai rispettivi responsabili.

resourceResolver.delete(resource);

resourceResolver.commit();

In questa pagina

Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now
Adobe Maker Awards Banner

Time to shine!

Apply now for the 2021 Adobe Experience Maker Awards.

Apply now