46 Line Blog, Revisited
Apache Sling’s tutorials include instructions to build a blog-like application with only 46 lines of code. This post is meant to step through the 46 Line Blog tutorial, accounting for new developments in Sling, and provide more context regarding the inner workings of Sling.
Overview
The application is a microblog-like application, capable of creating and managing short blog posts.
Let’s get into creating the application.
Get Apache Sling
You have the option of downloading pre-built binaries or building from source. I recommend using the latest Sling standalone distribution, which is version 8, at the time of writing.
If you do want to build Sling from source, consult the Sling documentation for getting and building Sling.
Run Apache Sling
Per Sling’s documentation, you’ll need Java 7 or higher to run Sling. Once you have your hands on your Sling distribution, you can run it like this:
java -jar org.apache.sling.launchpad-8.jar
This should start your Sling instance running at the default port of 8080. Navigating to http://localhost:8080/ should take you to the Sling Launchpad Welcome page.
Install the Path-Based RTP
Once you have Sling up and running, you’ll need to install the Apache Sling sample bundle for the Path-Based Resource Type Provider (RTP). You’ll need to build the bundle from source.
Why Build The RTP From Source?
At the time of writing, version 2.0.4 of the RTP bundle is available via the Sling Downloads page, but the code in that bundle version is based on an interface that was removed from Sling a loooong time ago. So, it won’t work with recent versions of Sling. And until a new version of the RTP bundle is released, you’ll need to create a 2.0.5 snapshot build.
Building the RTP From Source
Per Sling’s documentation, you’ll need Apache Maven, version 3.0.4 or later, in order to build the RTP from source. Follow these steps to do so:
Check out the Apache Sling source code
Change into the RTP directory (samples/path-based-rtp)
Install the RTP into your local Maven repository:
mvn install
After you follow these steps, the RTP should reside in your source code folder at samples/path-based-rtp/target/org.apache.sling.samples.path-based.rtp-2.0.5-SNAPSHOT.jar.
Install the RTP
After you build the RTP, you’ll need to install it into your Sling application.
To install the RTP, navigate to the web console of your Sling application at http://localhost:8080/system/console, and login with the username admin
, and the password admin
. You should be redirected to the “Bundles” page.
Click the “Install/Update” button on the “Bundles”, check the “Start Bundle” box, and click the “Choose File” button to navigate to your RTP build. Finally, click the “Install or Update” button to install the RTP.
Create the “New Post” Form
Create an HTML file, containing our “New Post” form, which will be used to create content in the form of blog posts.
If you have curl
, you should be able to use the following command to push the file directly from my GitHub gist to your locally running Sling instance:
curl -L https://gist.githubusercontent.com/briangoins/26eff8fda31c58369a8368fead6e16c2/raw/ffb64571c88ecfb9b504bf1928221fd25e447aee/blog.html | curl -u admin:admin -F"*@TypeHint=nt:file" -F"*=@-;filename=blog.html" http://localhost:8080/apps/blog
You can also use a WebDAV client to connect to http://localhost:8080 and save the file directly into the application.
You can verify that the file is present by navigating to http://localhost:8080/content/blog/*.html. You should see the blank “New Post” form.
Create A Post With The “New Post” Form
Once you have the RTP installed and the “New Post” form created, you can use the form to create new blog posts. Let’s test it out:
Navigate to your “New Post” form at http://localhost:8080/content/blog/*.html, and set the title as “Hello”, and the text as you wish. Click the “Save” button when you’re done.
You should end up at http://localhost:8080/blog/hello.html, looking at the same form, which should now be empty. Right now, this is what successfully creating a post looks like. Weird, I know, but please, keep reading.
Verifying Your New Post
So, where is the post?
Navigate to http://localhost:8080/blog/hello.json, and you should see a JSON representation of the post you just created, having the title and text that you specified when you filled and submitted the form.
You were actually redirected to the post you created after you submitted the “New Post” form. Unfortunately, our application currently renders the pages for our posts as an empty “New Post” form. Right now, we can see our post content by rendering it as JSON, but our HTML rendering is kind of broken.
Breakpoint: Explaining the Post Creation and Rendering
Let’s take a breather and explain what’s happened so far. If you’re just trying to work through the example, feel free to opt-out and go to the next section: “Improving the Post Rendering”.
The Main Thing About Sling
Put simply, the main thing to remember about Apache Sling is that it takes HTTP requests and gives you resources in exchange.
Sling does this by choosing a servlet to render the response for the HTTP request.
The Sling Post Servlet
An important servlet provided out-of-the-box by Sling is the SlingPostServlet
. It is the default servlet for servicing HTTP POST
requests in Sling, and can be used for creating content in your Sling applications.
So far, we’re using the Sling Post Servlet in two ways. First, we called curl
to push our HTML file with our “New Post” form into our application. When we did that, we issued a POST
request to our application, with certain parameters, and the Sling Post Servlet responded and created a new file in our application.
Second, we use our HTML form to issue POST
requests to our application, by specifying the method
on our form to be POST
, and filling and submitting that form. The Sling Post Servlet responds to the POST
requests issued by submitting the form, and creates content in our application as a result.
Read more about the Sling Post Servlet in it’s Sling documentation.
The Default Get Servlet and JSON Rendering
After we created our new post, (and saw our confusing HTML rendering of it,) we verified that our content was created correctly by rendering it as JSON.
This is another important servlet, the Sling Default Get Servlet at play. Like the Sling Post Servlet is the default servicer for POST
requests, the Default Get Servlet handles GET
requests by default.
Read more about the default JSON rendering in Sling in the JSON section of the Default Get Servlet documentation.
Scripts as Servlets
So, why is our empty form the HTML rendering of our new posts?
Our new posts render as the empty form because Sling has picked our blog.html
script as the servlet for rendering our post. Sling tries to pick a servlet to serve a response for HTTP requests it receives, and this can include scripts.
Script? Or HTML Document? The blog.html
file we uploaded to Sling is actually a script. More specifically, an HTL, or HTML Template Language, script. Sling’s HTL engine is one of the many scripting engines available in Sling.
This brings us to an important concept with Sling: that our scripts are also represented as servlets in Sling. And when Sling finds a script for rendering content, it’ll be used instead of the Default Get Servlet.
Read more about Sling servlets and scripts in the Sling documentation.
Sling Script Selection
We’ve established that Sling can pick a script to render content.
The main thing to remember about Sling script selection is that Sling will use a special property, called sling:resourceType
, to try and pick a script for rendering a piece of content. It’ll use the value of the property, and search locations in it’s search path (like /libs and /apps, by default) to find a script for rendering. You can read more about this in the Sling documentation.
We’ve seen that our new post only has three properties: jcr:primaryType
, text
, and title
. No sling:resourceType
property. So, how does Sling pick our blog.html
script for rendering?
This is where the Path-Based RTP comes in. It works inside Sling to pick a resource type when one isn’t provided.
The RTP eliminates some of the steps needed to get our 46 Line Blog working, and simplifies things so that we can create our application in 46 lines of code.
If you’re curious, you can look at the source of the Path-Based RTP in Sling’s Subversion repo or the GitHub repo mirror.
Improving the Post Rendering
Let’s fix our HTML rendering of our posts.
Curl command for update:
curl -L https://gist.githubusercontent.com/briangoins/eac8e2eb1062c9f0b60cff078130e763/raw/2961e6c1b174c1348439d01a48940186024a2a13/blog.html | curl -u admin:admin -F"*@TypeHint=nt:file" -F"*=@-;filename=blog.html" http://localhost:8080/apps/blog
This update leverages HTL scripting to fill in our form fields with their current values, when present. On line 8, we add an value
attribute to our title
form field, and on line 11, we add a body to our textarea
tag.
Now, when we look at our new post at http://localhost:8080/blog/hello.json, our form fields should be filled in with their current values.
Also, if we change either of the values, and press “Save”, the form should update with the new value we specify.
Adding Navigation
Let’s add another feature. We’re going to put navigation below our “New Post” form:
Curl command for update:
curl -L https://gist.githubusercontent.com/briangoins/114fa9fedec8a5b551e667b0dce4e63d/raw/c344bad68ab0702110432b441dd4e67d09e41f64/blog.html | curl -u admin:admin -F"*@TypeHint=nt:file" -F"*=@-;filename=blog.html" http://localhost:8080/apps/blog
So, on lines 22–29, we add a “Navigation” section, with an unordered list containing a “New Post” link, and links to the posts we’ve created already.
The unordered list leverages HTL again, to cycle through the posts in our blog, and output links. The expressions in this example use HTL global objects and Sling API calls on classes like Resource and ValueMap to create the list.
Adding Fields
We can easily add a field, like “author”, to our application:
Curl command for update:
curl -L https://gist.githubusercontent.com/briangoins/f81f8bae60bfdb3339d316e3ca6a69b4/raw/1bdfeb2b62bcb93027f5d62915551a72bb8745be/blog.html | curl -u admin:admin -F"*@TypeHint=nt:file" -F"*=@-;filename=blog.html" http://localhost:8080/apps/blog
Adding a new field is as simple as adding a new input
field to our HTML form, like in lines 13 and 14 in the example above.
As Bertrand Delacretaz explains in the original tutorial:
[This] allows us to add an author name to our blog posts. No need to define anything at the repository level, as Sling is using it in unstructured mode in this case, and no need to migrate existing data, the author field of existing posts will simply be empty.
Wrap-Up
The 46 Line Blog tutorial continues to be a good example of some of Sling’s features. Most of the ones used during this tutorial are explained in this post.
This post accounts for later distributions of Sling, and employs HTL scripting. The creation and Sling support of HTL are relatively new developments.
Thanks for reading! Read more about Apache Sling in it’s documentation.