AEM Guide

Come Sling risolve una richiesta verso un componente AEM

Come Sling trasforma un URL in una Resource e poi in un componente AEM tramite sling:resourceType, i search path /apps e /libs, e perché sling:resourceSuperType è il modo corretto per estendere i Core Components.

slingresourcetypecore-componentshtl

Quando AEM renderizza una pagina, ciò che accade realmente sotto è una risoluzione Sling in due passaggi: prima un URL diventa una Resource, poi quella Resource diventa un componente — uno script HTL o un servlet — che decide quale HTML viene restituito. Capire questa pipeline spiega perché /apps può prevalere su /libs, perché i Core Components si estendono con sling:resourceSuperType invece di essere sovrascritti direttamente, e perché un selettore sbagliato può rompere la cache del Dispatcher.

Dall’URL alla Resource

Quando arriva una richiesta come /content/miosito/it/home.html, Sling divide il percorso in resource path, selettori ed estensione, e usa il ResourceResolver per mappare /content/miosito/it/home su un nodo JCR reale. In un progetto AEM quel nodo è di solito una pagina (cq:Page), ma ciò che conta davvero per il rendering è il suo nodo jcr:content (o quello di un componente figlio), perché è lì che vive la proprietà sling:resourceType.

Da Resource a componente: sling:resourceType

sling:resourceType non è un percorso assoluto: è un percorso relativo che Sling cerca in un elenco ordinato di search path. Per esempio, se un componente ha:

sling:resourceType = "mioprogetto/components/hero"

Sling cerca uno script (.html, compilato da HTL a Java sotto il cofano) o un servlet il cui percorso, relativo a uno dei search path, corrisponde a mioprogetto/components/hero.

I search path di Sling: perché /apps viene prima di /libs

La configurazione predefinita di Sling (resource.resolver.searchpath) è ["/apps", "/libs"]. Questo significa che, per lo stesso sling:resourceType, Sling prova sempre prima lo script trovato sotto /apps rispetto a quello trovato sotto /libs. Questo è il meccanismo tecnico dietro il classico “overlay” di AEM: se una risorsa di prodotto vive in /libs/qualcosa/componente e tu metti uno script in /apps/qualcosa/componente, il tuo vince.

Su AEM as a Cloud Service, /libs è completamente immutabile: non ci distribuirai mai nulla. Questo overlay via search path è ancora reale per certe risorse di piattaforma che vivono ancora sotto /libs (parti di Granite UI o della console OSGi, ad esempio), ma non è il meccanismo da usare per estendere gli AEM Core Components — ed è un errore comune.

Perché i Core Components non si overlay-ano: sling:resourceSuperType

Gli AEM Core Components (core/wcm/components/...) vengono distribuiti come dipendenza del progetto e finiscono installati sotto /apps, non sotto /libs. Dato che sono già in /apps, non puoi “batterli” mettendo qualcosa sullo stesso sling:resourceType sotto /apps senza sostituire completamente il componente di prodotto — perdendo così qualsiasi miglioramento futuro rilasciato da Adobe.

Il modello corretto è l’ereditarietà dei componenti tramite sling:resourceSuperType:

<!-- /apps/mioprogetto/components/text/.content.xml -->
<jcr:root
    jcr:primaryType="cq:Component"
    jcr:title="Text"
    sling:resourceSuperType="core/wcm/components/text/v2/text"/>

Con questo, il tuo componente mioprogetto/components/text eredita tutto ciò che non sovrascrivi esplicitamente (dialog, script HTL, Sling Model) dal resourceSuperType. Se il tuo script HTL non definisce un certo blocco, Sling risale la catena di resourceSuperType finché non lo trova nel Core Component. Questo è ciò che ti permette di personalizzare solo il 10% che ti serve cambiare senza duplicare il restante 90%.

Selettori ed estensione cambiano anch’essi lo script scelto

I selettori e l’estensione della richiesta (.html, .json, un selettore come .print) entrano anch’essi nella risoluzione: Sling cerca prima uno script specifico per quella combinazione (text.print.html) prima di ricadere sullo script predefinito (text.html). È esattamente ciò su cui si basa il JSON Exporter di AEM (.model.json) per servire la rappresentazione Sling Model di un componente senza toccare il normale script di rendering.

Dove questo conta in un vero progetto AEM