Latest Posts

Archives [+]

Categories [+]

Authors [+]

How this blog is built (pt. 1)

If you followed the previous parts of this little microsling tutorial (here, here and here) you should now have microsling up and running. It’s time to move on and create a real web application with microsling. In this post I will explain how this blog system that you are currently reading has been built.

Content model

There is not too much information about structuring JCR content available (I hope to address this issue in the future). But one thing that is available is "David’s Model". I took it as the basis for structuring the blog.

Let’s see, there are blog posts, a blog entity to hold the posts, comments posted by readers and file attachments to blog posts. Now for the rules:

Rule #1: Data First, Structure Later. Maybe.

OK, that’s easy. I will store everything as nt:unstructured. Sounds good, did not want to think about node types anyway.

Rule #2: Drive the content hierarchy, don't let it happen.

This is a really good rule IMO. Especially, if one has done some relational DB modeling it is a bit hard to get into. But in our case it is easy and natural enough: blog posts will be children of the blog they belong to. Comments and attachments will be children of the post they belong to.

Rule #3: Workspaces are for clone(), merge() and update().

Actually, workspaces would be really useful for a staging area. However, I will not use them here in order to keep things simple.

Rule #4: Beware of Same Name Siblings.

This is no problem for the posts (I can just name them any way I like and there should not be too many), but I will come back to this regarding the user generated comments.

Rule #5: References considered harmful.

OK, I do not think I need them here.

Rule #6: Files are Files are Files.

I will use nt:file for attachments. Attachments are files after all.

Rule #7: ID's are evil.

I do not want to be evil. Hence, I do not use IDs (and I have not needed them so far).

Right, so the model looks something like this:

blog [nt:unstructured]
|  +sling:resourceType[string]
|--post [nt:unstructured]
|    +title[string]
|    +body[string]
|    +sling:resourceType[string]
|----comment [nt:unstructured]
|      +body[string]
|      +sling:resourceType[string]
|----attachment [nt:file]

Most of the properties should be self-explanatory (well, a blog post needs a title), but not the "sling:resourceType" properties. Since all nodes are unstructured (apart from the files) this additional property is needed for script resolution (see the post about microsling’s request processing). Microsling determines the resource type through this property (and indirectly the script to execute).

Display a blog post

Let’s now display a blog post. First, you need to create a post using CRX’s Content Explorer (see the last part of this tutorial if you are not sure how to do this). Create a blog node named "myblog". It shall contain a post node named "firstpost". Add a title and a body property.

The property "sling:resourceType" of the post shall have the value "blogPost". For the blog node the value shall be "blog".

You should get something like this:

Next, you need to put a script to display this node into the repository. The script must be placed in the directory "/sling/scripts/blogPost" and called "html.esp" (the server-side JavaScript processor will be used). The file shall contain:

<html>
  <body>
    <h1><%=resource.node.title%></h1>
    <%=resource.node.body%>
  </body>
</html>

To see the output of the script point your browser to http://localhost:7402/microsling/myblog/firstpost.html. As you already know, the bit between the <%= %> brackets is executed on the server and the result is inserted into the output. The resource object has a property node which represents the JCR node that was requested. This node has the two properties "title" and "body" which are accessed using JavaScript’s dot notation.

Display the whole blog

For displaying the whole blog you need to put a script called "html.esp" into "/sling/scripts/blog". The file shall contain:

<html>
  <body>
  <%
  for (var prop in resource.node) {
    if (resource.node[prop]["sling:resourceType"] == "blogPost") {
  %>
      <h1><%= resource.node[prop].title%></h1>
      <p><%= resource.node[prop].body%>
      </p>
  <%
    }
  }
  %>
  </body>
</html>

The parts between <% %>, (without the equals sign as opposed to above) denote JavaScript that is executed on the server without having the results being written into the output stream (that is just like JSPs again).

In the line

for (var prop in resource.node) {

the script iterates over the children of the blog node and looks for children of (Sling) resource type "blogPost" in this line:

if (resource.node[prop]["sling:resourceType"] == "blogPost") {

The square-bracket syntax for accessing a property (in this case ["sling:resourceType"]) is an alternative to the dot notation used above for title and body.

To see the output of the script point your browser to http://localhost:7402/microsling/myblog.html

An RSS feed and includes

Now that you have the list of posts it is really easy to add an additional feature: an RSS feed. For this, create a new script called xml.esp (i.e. it shall respond to requests ending in ".xml") and place it in "/sling/scripts/blog". The logic is almost the same as above, just the markup is different. Simply iterate over the blog posts and produce xml instead of html. So the file should contain:

<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>My blog </title>
<description>My blog</description>
<link>http://mydomain.com/microsling<%= resource %>.html"</link>
<%
  for (var prop in resource.node) {
    if (resource.node[prop]["sling:resourceType"] == "blogPost") {
      %><%=sling.include("/microsling"+\\
      resource.node[prop]+".rssitem.xml")%><%
    }
  }
%>
</channel>
</rss>

(The \\ characters shall denote that the line continues. Delete them from your code.)

The first new bit in this code is the expression <%= resource %>. This evaluates to the node name including the full path. It is useful e.g. for generating links as above.

The second new bit is the line

%><%=sling.include("/microsling"+\\
resource.node[prop]+".rssitem.xml")%><%

The include method generates a new request on the server-side. The result of this request is included into the output stream. This includes an alternative "view" of a blog post. "resource.node[prop]" is the node that contains the post. "rssitem" is a selector on this node. With a selector you can render a certain resource type in alternative ways. In this case you need to render a blog post as an rss feed item. Thus, create a script at "sling/scripts/blogPost/rssitem/xml.esp" that contains:

<item>
<title><%= resource.node.title %></title>
<description><%= resource.node.body%></description>
<link>http://mydomain.com/microsling<%= resource%>.html</link>
</item>

Now point your browser at http://localhost:7402/microsling/myblog.xml to see the resulting RSS feed.

OK, that’s all for today. In the next part, we will look at user-generated comments and attachments.

(For your convenience all the scripts have been added as an attachment to this post.)

 
(optional)
1 comment
OK, so when do we get to see the next part of the blog code in microsling?
0 Replies » Reply