Before we can get our feet wet with microsling I would like to spend another blog post on theory and explain two important concepts in microsling: the mapping of requests to resources and the script selection.
Microsling is content-centric. This means that each (http) request is mapped onto a JCR resource, i.e. a repository node. This is very different from other web frameworks you might be familiar with, say, Struts or Rails. In these conventional frameworks a request is mapped onto a controller, i.e. a url really addresses application code, so the application developer needs to implement some application logic that retrieves model data and passes it on to the view.
Just like Rails or Struts, microsling implements a model-view-controller architecture. However, in microsling a request addresses a piece of content. The mapping between request and model (data, content) is accomplished through the url so there is no need for further custom mapping logic.
Node selection
So, how does this work in detail? Consider an http request for the url:
First, microsling will look in the repository for a file located at exactly this location. If such a file is found, it will be streamed into the response as is. This behavior allows you to use microsling as a little web server and store your web application's binary data in the repository as well.
However, if there is no file to be found microsling will look for a repository node located at:
(i.e. it drops the file extension). If this node cannot be found it will truncate the node path and look for:
If this node does not exist either, it will look for
and so on. If nothing can be found under these paths it will finally select the special resource called "NonExistingResource". Consequently, there will always be a resource that each request can be mapped onto.
Script selection
Now that microsling has found a node it moves on to the second step and selects a script to display this node.
All of the scripts are stored in the repository as well. They reside in subfolders of "/sling/scripts", which are regular JCR nodes. Usually these nodes would be of type nt:folder (for example when they are created through WebDAV), but they do not have to be.
The selection algorithm for finding the right script to render the node takes into account the exact request url and the resource type of the selected resource. Let's go through the algorithm step-by-step:
- Choosing the script folder: In a first step the repository folder that contains the script is determined.
- The selected resource will have a resource type. This resource type can be set explicitly by adding a special property named "sling:resourceType" to the node. In this case the value of this property is the resource type of the node.
Say the value is "jobs/jobOffer", then microsling will select a script from the repository folder at "/sling/scripts/jobs/jobOffer/".
If the property "sling:resourceType" does not exist, the resource type will be determined from the node type of the node. Let's assume the node type is "nt:unstructured". In that case the folder located at "/sling/scripts/nt/unstructured/" will be selected (all colons in the resource type will be replaced by slashes).
- Next, there can be a so-called "selector" in the request url. It is an optional part that is appended to the resource and separated by a dot. Confused? Here's an example: if the requested url is /content/corporate/jobs/developer.summary.html the part "summary" would be the selector. If such a selector is present in the request it is appended to the path from above.
In this case the resulting path would be either "/sling/scripts/summary/jobs/jobOffer/" or "/sling/scripts/summary/nt/unstructured/" respectively.
Selectors are useful for creating different views on the same content item, e.g. to have a summary view and a full length view for an article.
- Once the folder is determined, the actual script file will be selected from this folder according to this algorithm:
- The file name will be the extension of the request, i.e. in our example from above /content/corporate/jobs/developer.summary.html the selected file will be named "html". In this way there can be various scripts for various response formats, one that handles requests for html pages, another one that handles json responses (in an Ajax application) and another that handles requests for PDFs.
- In order to get the complete file name of the script file we still need its file extension. It is through this file extension that microsling determines the script engine that shall process the script. For example, if the script file has an extension ".esp" then the (server-side) Javascript engine will execute the script, if it is ".rb" then JRuby will execute it. As such, the script author needs to name the script file's extension according to the scripting language he chooses to use. For a script written in JavaScript to produce html the file name would be "html.esp".
To sum up the script resolution so far, when microsling looks for a script it builds the path as:
Where:
- RT is the resource type
- (For the http GET method) ME is the extension found in the request (html, xml, etc.), always in lowercase.
- EXT is an extension that is acceptable for one of microsling's script engines (e.g. .esp, .rb, etc)
http method
You might have just stumbled over the "for the http GET method" bit and wondered "what about POST"? In fact, in addition to an extension like "html", ME can also be a http method like "POST". So if a POST request comes in, microsling will look for a script named POST., e.g. POST.esp. The convention is that http methods are all uppercase, whereas response types like "html" or "pdf" are all lowercase.
This should be enough background information to get you started. Don't worry, it may look a bit overwhelming at first glance, but you will get used to it quite quickly. Please find below an image representing the whole process.
There are some more subtleties and mechanisms in the url mapping to file names, taking into account additional parts of the url. My colleague Lars Trieloff has written an excellent post on his blog that goes into some more detail.
Thanks a lot to Bertrand, Felix, Alison and David for reviewing this post and providing a lot of corrections and useful feedback.