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:
- AEM
- Sling
- JCR
- 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:
com.adobe.cq
com.adobe.granite
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:
-
Costruzione di query con parametri semplice (parametri di query modellati come una mappa)
-
Predicati AEM che supportano i requisiti di query comuni
-
API estensibile, che consente lo sviluppo di predicati di query personalizzati
-
JCR-SQL2 e XPath possono essere eseguiti direttamente tramite Sling e API JCR, restituendo risultati rispettivamente come Sling Risorse o Nodi JCR.
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
-
Accesso ai nodi JCR come Sling Resources e ai relativi dati tramite ValueMaps.
-
Fornire contesto di sicurezza tramite ResourceResolver.
-
Creazione e rimozione di risorse tramite i metodi di creazione/spostamento/copia/eliminazione di ResourceResolver.
-
Aggiornamento delle proprietà tramite ModifiableValueMap.
-
Elaborazione di blocchi predefiniti di richiesta
-
Elaborazione asincrona dei blocchi predefiniti
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.
Usi comuni delle API JCR
-
Osservazione JCR (ascolto degli eventi JCR)
-
Creazione di strutture di nodi profondi
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
-
Annotazioni OSGi per dichiarare servizi e componenti OSGi.
- Preferisci Annotazioni di Servizi dichiarativi OSGi 1.2 rispetto a Annotazioni di Felix SCR per dichiarare servizi e componenti OSGi
-
API OSGi per l'annullamento/registrazione dinamica in codice dei servizi/componenti OSGi.
- Preferisci l’utilizzo delle annotazioni di OSGi DS 1.2 quando non è necessaria la gestione condizionale del servizio/componente OSGi (il che avviene il più delle volte).
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
acom.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).
- Mentre le API di Assets
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
- Sling registrazione servlet, preferisci annotazioni OSGi DS 1.2 con @SlingServletResourceTypes rispetto a
@SlingServlet
Registrazione filtro Sling sling-filter-registration
- Sling registrazione filtro, preferisci annotazioni di OSGi DS 1.2 con @SlingServletFilter rispetto a
@SlingFilter
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();