Best practice per le API Java™

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

L’AEM è basato su quattro set API Java™ primari.

  • Adobe Experience Manager (AEM)

    • Astrazioni di prodotto come pagine, risorse, flussi di lavoro, ecc.
  • Framework Web Apache Sling

    • Astrazioni REST e basate su risorse come risorse, mappe del valore e richieste HTTP.
  • JCR (Apache Jackrabbit Oak)

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

    • Astrazioni dei contenitori di applicazioni OSGi come servizi e componenti (OSGi).

Preferenza API Java™ "rule of thumb"

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

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

Se un'API è fornita dall'AEM, preferirla 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 eccezioni. Motivi accettabili per derogare a questa regola sono:

  • Eccezioni ben note, come descritto di seguito.

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

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

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

API AEM

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

Ad esempio, le API PageManager e Page dell'AEM forniscono astrazioni per cq:Page nodi nell'AEM che rappresentano pagine Web.

Sebbene questi nodi siano disponibili tramite API Sling come risorse e API JCR come nodi, le API AEM forniscono astrazioni per i casi d'uso comuni. L’utilizzo delle API dell’AEM garantisce un comportamento coerente tra l’AEM del prodotto e le personalizzazioni ed estensioni dell’AEM.

com.adobe.* rispetto a 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

Il pacchetto com.adobe.cq supporta casi di utilizzo di prodotti, mentre com.adobe.granite supporta casi di utilizzo di piattaforme tra più prodotti, ad esempio flussi di lavoro o attività (utilizzate tra i prodotti: AEM Assets, Sites e così via).

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

Le nuove astrazioni, ad esempio Content Fragments e Experience Fragments, vengono create nello spazio com.adobe.cq anziché com.day.cq come descritto di seguito.

API di query

L’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 in tutta la base di codice, per ridurre la complessità e i costi di comprensione.

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 rappresenta l'astrazione di livello più alto e fornisce un'API solida per la costruzione, l'esecuzione e il recupero dei risultati per le query, nonché le seguenti informazioni:

CAUTION
L’API QueryBuilder di AEM genera perdite in un oggetto ResourceResolver. Per limitare questa perdita, segui questo esempio di codice.

Sling API

Apache Sling è il framework web RESTful alla base dell'AEM. Sling fornisce il routing delle richieste HTTP, modella i nodi JCR come risorse, fornisce il contesto di sicurezza e molto altro.

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

Utilizzi comuni 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). Tutta l’implementazione JCR deve essere conforme a e implementare queste API, e quindi rappresenta l’API di livello più basso per interagire con i contenuti dell’AEM.

Il JCR stesso è un datastore NoSQL gerarchico/basato su struttura utilizzato dall’AEM come archivio dei contenuti. JCR dispone di una vasta gamma di API supportate, che vanno dal contenuto CRUD all’esecuzione di query sui contenuti. Nonostante questa robusta API, è raro che siano preferite rispetto alle astrazioni di livello superiore 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 errati comuni sulle API JCR

Mentre JCR è l’archivio dei contenuti dell’AEM, le sue API NON sono il metodo preferito per interagire con il contenuto. Preferisci invece le API AEM (Pagina, Assets, Tag e così via) o le API Sling Resource in quanto forniscono astrazioni migliori.

CAUTION
L’ampio utilizzo delle interfacce Sessione e Nodo delle API JCR in un’applicazione AEM è di tipo code-smell. Assicurati di utilizzare al suo posto Sling API.

Usi comuni delle API JCR

API OSGi

Vi è 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 nello sviluppo dell'AEM.

Confronto tra API OSGi e Apache Felix

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

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

Utilizzi comuni delle API OSGi

Eccezioni alla regola

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

API OSGi

Quando si tratta di astrazioni OSGi di basso livello, ad esempio la definizione o la lettura nelle proprietà dei componenti OSGi, le astrazioni più recenti fornite da org.osgi sono preferite alle astrazioni Sling di livello superiore. Le astrazioni Sling concorrenti non sono state contrassegnate come @Deprecated e suggeriscono l'alternativa org.osgi.

Inoltre, la definizione del nodo di configurazione OSGi preferisce cfg.json rispetto al formato sling:OsgiConfig.

API di AEM Asset

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

    • Mentre le API di Assets com.day.cq forniscono strumenti complementari per i casi d'uso della gestione delle risorse dell'AEM.
    • Le API di Granite Assets supportano casi d’uso di basso livello per la gestione delle risorse (versione, relazioni).

API di query

  • AEM QueryBuilder non supporta alcune funzioni di query, ad esempio suggerimenti, controllo ortografico e suggerimenti indice, oltre ad altre funzioni meno comuni. Per eseguire query con queste funzioni è preferibile utilizzare JCR-SQL2.

Registrazione servlet Sling sling-servlet-registration

Registrazione filtro Sling sling-filter-registration

Frammenti di codice utili

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

Sessione JCR a ResourceResolver Sling

ResourceResolver Sling con chiusura automatica

A partire da AEM 6.2, ResourceResolver Sling è 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) { .. }

ResourceResolver Sling chiuso manualmente

ResourceResolvers può essere chiuso manualmente in un blocco finally, se non è possibile utilizzare la tecnica di chiusura automatica illustrata 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 per Sling Resource

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

Nodo JCR a Sling Resource

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

Sling Resource alla risorsa AEM

Approccio consigliato

La funzione DamUtil.resolveToAsset(..) risolve qualsiasi risorsa sotto dam:Asset nell'oggetto Asset spostandosi verso l'alto nella struttura come necessario.

Asset asset = DamUtil.resolveToAsset(resource);

Approccio alternativo

L'adattamento di una risorsa a una risorsa richiede che la risorsa stessa sia il nodo dam:Asset.

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

Sling risorsa per pagina AEM

Approccio consigliato

pageManager.getContainingPage(..) risolve qualsiasi risorsa sotto cq:Page nell'oggetto Page spostandosi verso l'alto nella struttura, se necessario.

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 alternative-approach-1

L'adattamento di una risorsa a una pagina richiede che la risorsa stessa sia il nodo cq:Page.

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

Proprietà pagina Leggi AEM

Utilizzare i getter dell'oggetto Page per ottenere proprietà note (getTitle(), getDescription() e così via) e page.getProperties() per ottenere il ValueMap [cq:Page]/jcr:content per recuperare altre proprietà.

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

Proprietà metadati risorse AEM lette

L'API Asset fornisce metodi pratici per la lettura delle proprietà dal nodo [dam:Asset]/jcr:content/metadata. Questo non è un ValueMap, il secondo parametro (valore predefinito e cast di tipo automatico) non è supportato.

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

Lettura delle proprietà di Sling Resource read-sling-resource-properties

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

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 Sling Resource per individuare in modo efficiente la proprietà o la risorsa secondaria desiderata.

Pagina AEM a Sling Resource

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

Risorsa AEM a Sling Resource

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

Scrivere proprietà utilizzando ModifiableValueMap di Sling

Utilizza ModifiableValueMap di Sling per scrivere proprietà nei nodi. Questo può scrivere solo nel nodo immediato (i percorsi di proprietà relativi non sono supportati).

Nota: 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 pagine man mano che accetta 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(); }

Crea una risorsa Sling

ResourceResolver supporta operazioni di base per la creazione di risorse. Durante la creazione di astrazioni di livello superiore (pagine AEM, Assets, tag e così via), utilizza i metodi forniti dai rispettivi manager.

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

Elimina una risorsa Sling

ResourceResolver supporta la rimozione di una risorsa. Durante la creazione di astrazioni di livello superiore (pagine AEM, Assets, tag e così via), utilizza i metodi forniti dai rispettivi manager.

resourceResolver.delete(resource);

resourceResolver.commit();
recommendation-more-help
c92bdb17-1e49-4e76-bcdd-89e4f85f45e6