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 quattro set principali di API Java™.
Adobe Experience Manager (AEM)
Framework Web di Apache Sling
JCR (Apache Jackrabbit Oak)
OSGi (Apache Felix)
La regola generale è di preferire le API/astrazioni nel seguente ordine:
Se un’API viene fornita da AEM, preferiscila rispetto a Sling, JCR e OSGi. Se AEM non fornisce un'API, preferisci Sling su 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 un’API meno preferita e il costo per il passaggio alla nuova API non è giustificabile.
Le API 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.
Anche se questi nodi sono disponibili tramite Sling Le API as Resources e JCR API as Nodes AEM forniscono astrazioni per i casi d’uso comuni. L’utilizzo delle API AEM garantisce un comportamento coerente tra AEM prodotto e personalizzazioni ed estensioni a AEM.
AEM API hanno una preferenza intra-pacchetto, identificata dai seguenti pacchetti Java™, in ordine di preferenza:
com.adobe.cq
com.adobe.granite
com.day.cq
La com.adobe.cq
il pacchetto supporta i casi di utilizzo del prodotto, mentre com.adobe.granite
supporta casi di utilizzo tra piattaforme, ad esempio flussi di lavoro o attività, utilizzati tra i prodotti: AEM Assets, Sites e così via).
La com.day.cq
il pacchetto contiene le API "originali". Queste API riguardano le astrazioni e le funzionalità principali esistenti prima e/o intorno all’acquisizione di Adobe 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 quali Content Fragments e Experience Fragments sono incorporati in com.adobe.cq
spazio anziché com.day.cq
descritto di seguito.
AEM supporta più linguaggi di query. Le tre lingue principali sono JCR-SQL2, XPath e Query Builder AEM.
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, come Apache Oak le trasferisce a JCR-SQL2 per l'esecuzione della query finale e il tempo di conversione a JCR-SQL2 è trascurabile rispetto al tempo di query stesso.
L’API preferita è Query Builder AEM, che rappresenta 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:
Struttura semplice e parametrizzata delle query (parametri di query modellati come mappa)
Nativo API Java™ e HTTP
predicati AEM supporto dei requisiti comuni di query
API estensibile, che consente lo sviluppo di predicati query
JCR-SQL2 e XPath possono essere eseguiti direttamente tramite Sling e API JCR, risultati restituiti Sling Risorse o Nodi JCR, rispettivamente.
AEM API QueryBuilder perde un oggetto ResourceResolver. Per attenuare questa perdita, segui questo esempio di codice.
Apache Sling è il framework web RESTful su cui si fonda 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 incrementare il comportamento delle applicazioni create utilizzando Sling API rispetto alle API JCR meno estensibili.
Accesso ai nodi JCR come Sling Resources e l'accesso ai loro dati tramite ValueMaps.
Fornire un contesto di sicurezza tramite il ResourceResolver.
Creazione e rimozione di risorse tramite ResourceResolver metodi create/move/copy/delete.
Aggiornamento delle proprietà tramite ModificabileValueMap.
Blocchi predefiniti per l’elaborazione delle richieste di generazione
Blocchi predefiniti per l’elaborazione del lavoro asincrono
La API JCR (Java™ Content Repository) 2.0 fa parte di una specifica per le implementazioni JCR (nel caso di AEM, Apache Jackrabbit Oak). Tutte le implementazioni JCR devono essere conformi e implementate a queste API, ed è quindi l’API di livello più basso per interagire con i contenuti AEM.
Il JCR stesso è un datastore NoSQL gerarchico/basato su albero AEM utilizza 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 al AEM di livello superiore 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.
Anche se JCR è AEM archivio di contenuti, le sue API NON sono il metodo preferito per interagire con il contenuto. Preferiscono invece le API AEM (Pagina, Risorse, Tag e così via) o Sling Resource API in quanto forniscono migliori astrazioni.
L'ampio utilizzo delle interfacce Session e Node delle API JCR in un'applicazione AEM è un odore di codice. Assicurati Sling È invece necessario utilizzare le API.
Osservazione JCR (ascolto di eventi JCR)
Creazione di strutture dei nodi profondi
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.
OSGi definisce una specifica a cui tutti i contenitori OSGi devono implementare e conformarsi. AEM implementazione OSGi, Apache Felix, fornisce anche diverse proprie API.
org.osgi
) sulle API di Apache Felix (org.apache.felix
).Annotazioni OSGi per dichiarare i servizi e i componenti OSGi.
API OSGi per codice dinamico annullamento/registrazione dei servizi/componenti OSGi.
Di seguito sono riportate alcune eccezioni comuni alle regole definite in precedenza.
Quando si tratta di astrazioni OSGi di basso livello, come definire o leggere nelle proprietà dei componenti OSGi, le più recenti astrazioni fornite da org.osgi
sono preferite rispetto alle astrazioni Sling di livello superiore. Le astrazioni Sling concorrenti non sono state contrassegnate come @Deprecated
e suggeriscono org.osgi
alternativa.
Nota anche che la definizione del nodo di configurazione OSGi preferisce cfg.json
su sling:OsgiConfig
formato.
Preferisci com.day.cq.dam.api
over com.adobe.granite.asset.api
.
com.day.cq
Le API di Assets forniscono strumenti più gratuiti per AEM casi d’uso di gestione delle risorse.@SlingServlet
@SlingFilter
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.
A partire dal AEM 6.2, il Sling ResourceResolver è AutoClosable
in try-with-resources istruzione. Utilizzando questa sintassi, effettua 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 può essere chiuso manualmente in un 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(); }
}
Resource resource = ResourceResolver.getResource("/path/to/the/resource");
Resource resource = resourceResolver.getResource(node.getPath());
La DamUtil.resolveToAsset(..)
risolve qualsiasi risorsa in dam:Asset
per accedere all’oggetto Asset, risalendo la struttura ad albero come necessario.
Asset asset = DamUtil.resolveToAsset(resource);
L’adattamento di una risorsa a una risorsa richiede che la risorsa stessa sia dam:Asset
nodo.
Asset asset = resource.adaptTo(Asset.class);
pageManager.getContainingPage(..)
risolve qualsiasi risorsa in 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");
L’adattamento di una risorsa a una pagina richiede che la risorsa stessa sia cq:Page
nodo.
Page page = resource.adaptTo(Page.class);
Utilizza i getters dell’oggetto Page per ottenere proprietà ben note (getTitle()
, getDescription()
e così via) e page.getProperties()
per ottenere [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());
L’API delle risorse fornisce metodi utili per la lettura delle proprietà dalla [dam:Asset]/jcr:content/metadata
nodo. Questo non è 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");
Quando le proprietà sono memorizzate in posizioni (proprietà o risorse relative) a cui non è possibile accedere direttamente dalle API AEM (Pagina, Risorsa), l’ Sling Per ottenere i dati è possibile utilizzare le 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.
Resource resource = page.adaptTo(Resource.class);
Resource resource = asset.adaptTo(Resource.class);
Utilizzo Slings ModificabileValueMap per scrivere proprietà sui nodi. Questo può solo scrivere sul nodo immediato (i percorsi delle proprietà relative 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();
Utilizzare sempre PageManager per creare 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(); }
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();
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();