AEM is built using Sling, a Web application framework based on REST principles that provides easy development of content-oriented applications. Sling uses a JCR repository, such as Apache Jackrabbit, or in the case of AEM, the CRX Content Repository, as its data store.
The following diagram explains Sling script resolution:
The following diagram explains all the hidden, but powerful, request parameters you can use when dealing with the SlingPostServlet, the default handler for all POST requests that gives you endless options for creating, modifying, deleting, copying and moving nodes in the repository.
Sling is Content Centric
Sling is content-centric. This means that processing is focused on the content as each (HTTP) request is mapped onto content in the form of a JCR resource (a repository node): the first target is the resource (JCR node) holding the content
secondly, the representation, or script, is located from the resource properties in combination with certain parts of the request (e.g. selectors and/or the extension)
RESTful Sling
Due to the content-centric philosophy, Sling implements a REST-oriented server and thus features a new concept in web application frameworks. The advantages are:
very RESTful, not just on the surface; resources and representations are correctly modelled inside the server
removes one or more data models
previously the following were needed: URL structure, business objects, DB schema;
this is now reduced to: URL = resource = JCR structure
URL Decomposition
In Sling, processing is driven by the URL of the user request. This defines the content to be displayed by the appropriate scripts. To do this, information is extracted from the URL.
If we analyze the following URL:
http://myhost/tools/spy.printable.a4.html/a/b?x=12
We can break it down into its composite parts:
protocol | host | content path | selector(s) | extension | suffix | param(s) | ||
http:// | myhost | tools/spy | .printable.a4. | html | / | a/b | ? | x=12 |
host : Name of the website.
content path : Path specifying the content to be rendered. Is used in combination with
the extension; in this example they translate to tools/spy.html.
selector(s) : Used for alternative methods of rendering the content; in this example a printer-friendly version in A4 format.
extension : Content format; also specifies the script to be used for rendering.
suffix : Can be used to specify additional information.
param(s) : Any parameters required for dynamic content.
From URL to Content and Scripts
Using these principles:
From URL to Content and Scripts
Using these principles:
- the mapping uses the content path extracted from the request to locate the resource
- when the appropriate resource is located, the sling resource type is extracted, and used to locate the script to be used for rendering the content
The figure below illustrates the mechanism used, which will be discussed in more detail in the following sections.
With Sling, you specify which script renders a certain entity (by setting the sling:resourceType property in the JCR node). This mechanism offers more freedom than one in which the script accesses the data entities (as an SQL statement in a PHP script would do) as a resource can have several renditions.
Mapping requests to resources
The request is broken down and the necessary information extracted. The repository is searched for the requested resource (content node):
Locating the script
When the appropriate resource (content node) is located, the sling resource type is extracted. This is a path, which locates the script to be used for rendering the content.
The path specified by the sling:resourceType can be either:
With Sling, you specify which script renders a certain entity (by setting the sling:resourceType property in the JCR node). This mechanism offers more freedom than one in which the script accesses the data entities (as an SQL statement in a PHP script would do) as a resource can have several renditions.
Mapping requests to resources
The request is broken down and the necessary information extracted. The repository is searched for the requested resource (content node):
- first Sling checks whether a node exists at the location specified in the request; e.g. ../content/corporate/jobs/developer.html
- if no node is found, the extension is dropped and the search repeated; e.g. ../content/corporate/jobs/developer
- if no node is found then Sling will return the http code 404 (Not Found).
Locating the script
When the appropriate resource (content node) is located, the sling resource type is extracted. This is a path, which locates the script to be used for rendering the content.
The path specified by the sling:resourceType can be either:
- absolute
- relative, to a configuration parameter
- Relative paths are recommended by Adobe as they increase portability.
A few other points to note are:
when the Method (GET, POST) is required, it will be specified in uppercase as according to the HTTP specification e.g. jobs.POST.esp (see below)
various script engines are supported:
when the Method (GET, POST) is required, it will be specified in uppercase as according to the HTTP specification e.g. jobs.POST.esp (see below)
various script engines are supported:
- .esp, .ecma: ECMAScript (JavaScript) Pages (server-side execution)
- .jsp: Java Server Pages (server-side execution)
- .java: Java Servlet Compiler (server-side execution)
- .jst: JavaScript templates (client-side execution)
Using the above example, if the sling:resourceType is hr/jobs then for:
- GET/HEAD requests, and URLs ending in .html (default request types, default format)
- The script will be /apps/hr/jobs/jobs.esp; the last section of the sling:resourceType forms the file name.
- POST requests (all request types excluding GET/HEAD, the method name must be uppercase)
- POST will be used in the script name.
- The script will be /apps/hr/jobs/jobs.POST.esp.
- URLs in other formats, not ending with .html
- For example ../content/corporate/jobs/developer.pdf
- The script will be /apps/hr/jobs/jobs.pdf.esp; the suffix is added to the script name.
- URLs with selectors
- Selectors can be used to display the same content in an alternative format. For example a printer friendly version, an rss feed or a summary.
- If we look at a printer friendly version where the selector could be print; as in ../content/corporate/jobs/developer.print.html
- The script will be /apps/hr/jobs/jobs.print.esp; the selector is added to the script name.
- If no sling:resourceType has been defined then:
- the content path will be used to search for an appropriate script (if the path based ResourceTypeProvider is active).
- For example, the script for ../content/corporate/jobs/developer.html would generate a search in /apps/content/corporate/jobs/.
- the primary node type will be used.
- If no script is found at all then the default script will be used.
- The default rendition is currently supported as plain text (.txt), HTML (.html) and JSON (.json), all of which will list the node’s properties (suitably formatted). The default rendition for the extension .res, or requests without a request extension, is to spool the resource (where possible).
- For http error handling (codes 403 or 404) Sling will look for a script at either:
- the location /apps/sling/servlet/errorhandler for customized scripts
- or the location of the standard scripts /libs/sling/servlet/errorhandler/403.esp, or 404.esp respectively.
If multiple scripts apply for a given request, the script with the best match is selected. The more specific a match is, the better it is; in other words, the more selector matches the better, regardless of any request extension or method name match.
For example, consider a request to access the resource
/content/corporate/jobs/developer.print.a4.html
of type
sling:resourceType=”hr/jobs”
Assuming we have the following list of scripts in the correct location:
/content/corporate/jobs/developer.print.a4.html
of type
sling:resourceType=”hr/jobs”
Assuming we have the following list of scripts in the correct location:
- GET.esp
- jobs.esp
- html.esp
- print.esp
- print.html.esp
- print/a4.esp
- print/a4/html.esp
- print/a4.html.esp
Then the order of preference would be (8) – (7) – (6) – (5) – (4) – (3) – (2) – (1).
In addition to the resource types (primarily defined by the sling:resourceType property) there is also the resource super type. This is generally indicated by the sling:resourceSuperType property. These super types are also considered when trying to find a script. The advantage of resource super types is that they may form a hierarchy of resources where the default resource type sling/servlet/default (used by the default servlets) is effectively the root.
The resource super type of a resource may be defined in two ways:
by the sling:resourceSuperType property of the resource.
by the sling:resourceSuperType property of the node to which the sling:resourceType points.
/
Sling Scripts cannot be called directly
Within Sling, scripts cannot be called directly as this would break the strict concept of a REST server; you would mix resources and representations.
In addition to the resource types (primarily defined by the sling:resourceType property) there is also the resource super type. This is generally indicated by the sling:resourceSuperType property. These super types are also considered when trying to find a script. The advantage of resource super types is that they may form a hierarchy of resources where the default resource type sling/servlet/default (used by the default servlets) is effectively the root.
The resource super type of a resource may be defined in two ways:
by the sling:resourceSuperType property of the resource.
by the sling:resourceSuperType property of the node to which the sling:resourceType points.
/
- a
- b
- sling:resourceSuperType = a
- c
- sling:resourceSuperType = b
- x
- sling:resourceType = c
- y
- sling:resourceType = c
- sling:resourceSuperType = a
The type hierarchy of /x is [ c, b, a, <default>] while for /y the hierarchy is [ c, a, <default>] because /y has the sling:resourceSuperType property whereas /x does not and therefore its supertype is taken from its resource type.
Sling Scripts cannot be called directly
Within Sling, scripts cannot be called directly as this would break the strict concept of a REST server; you would mix resources and representations.
If you call the representation (the script) directly you hide the resource inside your script, so the framework (Sling) no longer knows about it. Thus you lose certain features:
- automatic handling of http methods other than GET, including:
- POST, PUT, DELETE which are handled with a sling default implementation
- the POST.jsp script in your sling:resourceType location
- your code architecture is no longer as clean nor as clearly structured as it should be; of prime importance for large-scale development
Sling API
This uses the Sling API package, org.apache.sling.*, and tag libraries.
Referencing existing elements using sling:include
A final consideration is the need to reference existing elements within the scripts.
More complex scripts (aggregating scripts) might need to access multiple resources (for example navigation, sidebar, footer, elements of a list) and do so by including the resource.
To do this you can use the sling:include(“/<path>/<resource>”) command. This will effectively include the definition of the referenced resource, as in the following statement which references an existing definition for rendering images:
%><sling:includeresourceType="geometrixx/components/image/img"/><%
Using Sling Adapters
Sling offers an Adapter pattern to conveniently translate objects that implement the Adaptable interface. This interface provides a generic adaptTo() method that will translate the object to the class type being passed as the argument.
For example to translate a Resource object to the corresponding Node object, you can simply do:
Node node = resource.adaptTo(Node.class);
Null Return Value
adaptTo() can return null.
There are various reasons for this, including:
the implementation does not support the target type
an adapter factory handling this case is not active (eg. due to missing service references)
internal condition failed
service is not available
It is important that you handle the null case gracefully. For jsp renderings it might be acceptable to have the jsp fail if that will result in an empty piece of content.
Caching
To improve performance, implementations are free to cache the object returned from a obj.adaptTo() call. If the obj is the same, the returned object is the same.
This caching is performed for all AdapterFactory based cases.
However, there is no general rule – the object could be either a new instance or an existing one. This means that you cannot rely on either behavior. Hence it is important, especially inside AdapterFactory, that objects are reusable in this scenario.
How it works
There are various ways that Adaptable.adaptTo() can be implemented:
Reference
Sling
Resource adapts to:
ResourceResolver adapts to:
SlingHttpServletRequest adapts to:
No targets yet, but implements Adaptable and could be used as source in a custom AdapterFactory.
SlingHttpServletResponse adapts to:
WCM
Page adapts to:
Component adapts to:
Template adapts to:
Security
Authorizable, User and Group adapt to:
DAM
Asset adapts to:
Tagging
Tag adapts to:
Other
Furthermore Sling / JCR / OCM also provides an AdapterFactory for custom OCM (Object Content Mapping) objects.
This uses the Sling API package, org.apache.sling.*, and tag libraries.
Referencing existing elements using sling:include
A final consideration is the need to reference existing elements within the scripts.
More complex scripts (aggregating scripts) might need to access multiple resources (for example navigation, sidebar, footer, elements of a list) and do so by including the resource.
To do this you can use the sling:include(“/<path>/<resource>”) command. This will effectively include the definition of the referenced resource, as in the following statement which references an existing definition for rendering images:
%><sling:includeresourceType="geometrixx/components/image/img"/><%
Using Sling Adapters
Sling offers an Adapter pattern to conveniently translate objects that implement the Adaptable interface. This interface provides a generic adaptTo() method that will translate the object to the class type being passed as the argument.
For example to translate a Resource object to the corresponding Node object, you can simply do:
Node node = resource.adaptTo(Node.class);
Null Return Value
adaptTo() can return null.
There are various reasons for this, including:
the implementation does not support the target type
an adapter factory handling this case is not active (eg. due to missing service references)
internal condition failed
service is not available
It is important that you handle the null case gracefully. For jsp renderings it might be acceptable to have the jsp fail if that will result in an empty piece of content.
To improve performance, implementations are free to cache the object returned from a obj.adaptTo() call. If the obj is the same, the returned object is the same.
This caching is performed for all AdapterFactory based cases.
However, there is no general rule – the object could be either a new instance or an existing one. This means that you cannot rely on either behavior. Hence it is important, especially inside AdapterFactory, that objects are reusable in this scenario.
How it works
There are various ways that Adaptable.adaptTo() can be implemented:
- By the object itself; implementing the method itself and mapping to certain objects.
- By an AdapterFactory, which can map arbitrary objects.
- The objects must still implement the Adaptable interface and must extend SlingAdaptable (which passes the adaptTo call to a central adapter manager).
- This allows hooks into the adaptTo mechanism for existing classes, such as Resource.
- A combination of both.
Reference
Sling
Resource adapts to:
Node | If this is a JCR-node-based resource or a JCR property referencing a node. |
Property | If this is a JCR-property-based resource. |
Item | If this is a JCR-based resource (node or property). |
Map | Returns a map of the properties, if this is a JCR-node-based resource (or other resource supporting value maps). |
ValueMap | Returns a convenient-to-use map of the properties, if this is a JCR-node-based resource (or other resource supporting value maps). Can also be achieved (more simply) by using ResourceUtil.getValueMap(Resource) (handles null case, etc.). |
InheritanceValueMap | Extension of ValueMap which allows the hierarchy of resources to be taken into account when looking for properties. |
PersistableValueMap | If this is a JCR-node-based resource and the user has permissions to modify properties on that node. Note: multiple persistable maps do not share their values. |
InputStream | Returns the binary content of a “file” resource (if this is a JCR-node-based resource and the node type is nt:file or nt:resource; if this is a bundle resource; file content if this is a file system resource) or the data of a binary JCR property resource. |
URL | Returns a URL to the resource (repository URL of this node if this is a JCR-node-based resource; jar bundle URL if this is a bundle resource; file URL if this is a file system resource). |
File | If this is a file system resource. |
SlingScript | If this resource is a script (e.g. jsp file) for which a script engine is registered with sling. |
Servlet | If this resource is a script (e.g. jsp file) for which a script engine is registered with sling or if this is a servlet resource. |
Authorizable (Jackrabbit) | If this is a an authorizable resource (from the AuthorizableResourceProvider in org.apache.sling.jackrabbit.usermanager, under /system/userManager). |
String Boolean Long Double Calendar Value String[] Boolean[] Long[] Calendar[] Value[] | Returns the value(s) if this is a JCR-property-based resource (and the value fits). |
LabeledResource | If this is a JCR-node-based resource. |
Page | If this is a JCR-node-based resource and the node is a cq:Page (or cq:PseudoPage). |
Component | If this is a cq:Component node resource. |
Design | If this is a design node (cq:Page, typically under /etc/designs). |
Template | If this is a cq:Template node resource. |
Blueprint | If this is a cq:Page node resource (more specific checks possible in the future). |
Asset | If this is a dam:Asset node resource. |
Rendition | If this is a dam:Asset rendition (nt:file under the rendition folder of a dam:Assert) |
Tag | If this is a cq:Tag node resource. |
Preferences | If this is a cq:Preferences node resource for a valid user/group. |
Profile | If this is the profile below a user/group node (eg. cq/security/components/profile). |
UserManager | Based on the JCR session if this is a JCR-based resource and the user has permissions to access the UserManager. |
Authorizable (cq-security) | This is a authorizable home node. |
User (cq-security) | If this is a user home node. |
PrivilegeManager | |
SimpleSearch | Searches below the resource (or use setSearchIn()) if this is a JCR-based resource. |
WorkflowStatus | Workflow status for the given page/workflow payload node. |
ReplicationStatus | Replication status for the given resource or its jcr:content subnode (checked first). |
ConnectorResource | Returns an adapted connector resource for certain types, if this is a JCR-node-based resource. |
Config | If this is a cq:ContentSyncConfig node resource. |
ConfigEntry | If this is below a cq:ContentSyncConfig node resource. |
Session | The request’s JCR session, if this is a JCR-based resource resolver (default). |
PageManager | |
ComponentManager | |
Designer | |
AssetManager | Based on the JCR session, if this is a JCR-based resource resolver. |
TagManager | Based on the JCR session, if this is a JCR-based resource resolver. |
UserManager | Based on the JCR session, if this is a JCR-based resource resolver, and if the user has permissions to access the UserManager. |
Authorizable | The current user. |
User | The current user. |
PrivilegeManager | |
Preferences | Preferences of the current user (based on JCR session if this is a JCR-based resource resolver). |
PreferencesService | |
PinManager | |
QueryBuilder | |
Externalizer | For externalizing absolute URLs, even with out the request object. |
No targets yet, but implements Adaptable and could be used as source in a custom AdapterFactory.
SlingHttpServletResponse adapts to:
ContentHandler (XML) | If this is a sling rewriter response. |
Page adapts to:
Resource | Resource of the page. |
LabeledResource | Labeled resource (== this). |
Node | Node of the page. |
… | Everything that the page’s resource can be adapted to. |
Resource | Resource of the component. |
LabeledResource | Labeled resource (== this). |
Node | Node of the component. |
… | Everything that the component’s resource can be adapted to. |
Resource | Resource of the template. |
LabeledResource | Labeled resource (== this). |
Node | Node of this template. |
… | Everything that the template’s resource can be adapted to. |
Authorizable, User and Group adapt to:
Node | Returns the user/group home node. |
ReplicationStatus | Returns the replication status for the user/group home node. |
Asset adapts to:
Tag adapts to:
Furthermore Sling / JCR / OCM also provides an AdapterFactory for custom OCM (Object Content Mapping) objects.
No comments:
Post a Comment
If you have any doubts or questions, please let us know.