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, preferiscila rispetto a Sling, JCR e OSGi. Se l’AEM non fornisce un’API, preferisci Sling su 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, AEM PageManager e Pagina Le API forniscono astrazioni per cq:Page nodi in AEM che rappresentano pagine web.

Mentre questi nodi sono disponibili tramite Sling API come Risorse e API JCR come Nodi, le API AEM forniscono astrazioni per 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 com.adobe.cq supporta casi di utilizzo di prodotti, mentre com.adobe.granite supporta casi di utilizzo per più piattaforme, ad esempio flusso di lavoro o attività (utilizzate tra prodotti diversi: AEM Assets, Sites e così via).

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

Nuove astrazioni come Content Fragments e Experience Fragments sono integrate in com.adobe.cq spazio anziché com.day.cq descritte di seguito.

API di query

L’AEM supporta più linguaggi di query. Le tre lingue principali sono JCR-SQL2, XPath e Generatore di query AEM.

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, come 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 è Generatore di query AEM, che è l’astrazione di livello più alto e fornisce una solida API per la costruzione, l’esecuzione e il recupero dei risultati delle query, oltre a:

CAUTION
L’API QueryBuilder di AEM genera perdite in un oggetto ResourceResolver. Per limitare questa perdita, segui questa procedura 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 Le API presentano il vantaggio aggiunto di essere create per l’estensione, il che significa che spesso è più semplice e sicuro incrementare il comportamento delle applicazioni create utilizzando Sling rispetto alle API JCR meno estensibili.

Utilizzi comuni di Sling API

API JCR

Il API JCR (Java™ Content Repository) 2.0 fa parte di una specifica per le implementazioni JCR (nel caso dell’AEM, Apache Jackrabbit Oak). Tutta l’implementazione JCR deve essere conforme a e implementare queste API, e rappresenta quindi il livello più basso di API 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 al livello superiore AEM e Sling astrazioni.

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

Concetti errati comuni sulle API JCR

Anche se JCR è un archivio di contenuti AEM, le sue API NON sono il metodo preferito per interagire con il contenuto. Preferisci invece le API AEM (Pagina, Risorse, 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. Assicurare Sling Al suo posto, utilizza le API.

Usi comuni delle API JCR

API OSGi

Vi è poca sovrapposizione tra le API OSGi e le API di livello superiore (AEM, Slinge JCR) e la necessità di utilizzare le API OSGi è rara e richiede un elevato 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 dell’AEM, Apache Felix, fornisce anche diverse API proprie.

  • Preferisci API OSGi (org.osgi) sulle 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, come la definizione o la lettura delle proprietà dei componenti OSGi, le astrazioni più recenti fornite da org.osgi sono preferite rispetto alle astrazioni Sling di livello superiore. Le astrazioni Sling concorrenti non sono state contrassegnate come @Deprecated e suggerisci org.osgi alternativa.

Inoltre, tieni presente che la definizione del nodo di configurazione OSGi preferisce cfg.json oltre il sling:OsgiConfig formato.

API di AEM Asset

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

    • Mentre il com.day.cq Le API Assets forniscono strumenti complementari per i casi d’uso della gestione delle risorse 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 come suggerimenti, controllo ortografico e suggerimenti per l'indicizzazione, oltre ad altre funzioni meno comuni. Per eseguire query con queste funzioni è preferibile utilizzare JCR-SQL2.

Sling Registrazione servlet sling-servlet-registration

Sling Registrazione filtro 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 Sling ResourceResolver

ResourceResolver Sling con chiusura automatica

A partire dall'AEM 6.2, la Sling ResourceResolver è AutoClosable in un try-with-resources dichiarazione. Utilizzando questa sintassi, una chiamata esplicita a resourceResolver .close() non è necessario.

@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 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 a AEM Asset

Approccio consigliato

Il DamUtil.resolveToAsset(..) funzione risolve qualsiasi risorsa sotto il dam:Asset all’oggetto Asset spostandosi verso l’alto nella struttura, se necessario.

Asset asset = DamUtil.resolveToAsset(resource);

Approccio alternativo

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

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

Sling Pagina Risorsa per AEM

Approccio consigliato

pageManager.getContainingPage(..) risolve le risorse sotto cq:Page all'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 la cq:Page nodo.

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 [cq:Page]/jcr:content ValueMap 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 leggere le proprietà da [dam:Asset]/jcr:content/metadata nodo. 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");

Letto Sling Resource proprietà read-sling-resource-properties

Quando le proprietà sono memorizzate in posizioni (proprietà o risorse relative) in cui le API AEM (Pagina, Risorsa) non possono accedere direttamente, il Sling È possibile utilizzare le risorse 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, l’oggetto AEM potrebbe dover essere convertito in un 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);

Scrivi proprietà tramite SlingModifiableValueMap

Utilizzare Slingdi ModifiableValueMap per scrivere le 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(); }

Creare un Sling Risorsa

ResourceResolver supporta operazioni di base per la creazione di risorse. Quando crei astrazioni di livello superiore (pagine AEM, risorse, 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();

Eliminare un Sling Risorsa

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

resourceResolver.delete(resource);

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