Developing a Simple Blog

You are reading the CRX 2.1 version of Developing a Simple Blog.
This documentation is also available for the following versions: CRX 2.2 

This example is intended as basic introduction to developing with CRX (together with CRXDE Lite). We will develop a simple Blog covering:

Note

The example uses a standard installation at:
    http://localhost:7402/

If you have installed CRX at another location, then substitute this with:
    http://<server-name>:<port-number>/
for example http://localhost:4502/

Note

This is a very simple blog, for real life usage extension would be necessary.

Creating the Root Page

For ease of usage we are going to create the entire blog under one page.

  1. Using CRXDE Lite, navigate to /content in the repository.

  2. Select /content then using the context menu (usually the right mouse button) select Create... followed by Create Node.... The dialog that opens allows you to specify:

    • Name: as required, for example myBlog.
    • Type: select nt:unstructured
  3. Click OK to save.

  4. Select the new node myBlog.

  5. Create a new property:

    • Name: title
    • Type: String
    • Value: as required; for example, My Blog

    Click Add (the green plus icon) to add the property to the list.

  6. Create another new property:

    • Name: body
    • Type: String
    • Value: as required; for example, Mine, all mine.

    Click Add (the green plus icon)to add the property to the list.

  7. Click Save All.

Creating Individual Pages for each Post

Under the root page we will create a (self-imposed) structure for the individual posts. As this is a chronological blog we can use a simple structure based on dates.

  1. Under the node myBlog create a new node:

    • Name: 2010
    • Type: nt:unstructured
    • Properties:
      • Name: title
      • Type: String
      • Value: 2010

      • Name: body
      • Type: String
      • Value: All entries for 2010.
  2. Under the node 2010 create a new node:

    • Name: March
    • Type: nt:unstructured
    • Properties:
      • Name: title
      • Type: String
      • Value: March 2010

      • Name: body
      • Type: String
      • Value: All entries for March 2010.
  3. Under the node March create a new node:

    • Name: 01March2010
    • Type: nt:unstructured
    • Properties:
      • Name: title
      • Type: String
      • Value: 1st March 2010

      • Name: body
      • Type: String
      • ValueSunny.<br>First day of meteorological spring.
  4. Under the node March create another new node:

    • Name: 02March2010
    • Type: nt:unstructured
    • Properties:
      • Name: title
      • Type: String
      • Value: 2nd March 2010

      • Name: body
      • Type: String
      • Value: Cloudy with sunny spells.
  5. Click Save All.

Rendering your Blog as HTML Pages

How a resource is rendered depends on the extension and selector used. These are used to select the script used for the rendering.

To render a resource as HTML the resource is selected with the extension .html, this then uses the script html.jsp. As we have not explicitly defined the sling:resourceType property on any of our nodes, the script will be taken from /apps/myBlog (the path is derived from the content path /content/myBlog).

Displaying the title and body

As a basic example we want to display the contents of the two properties title and body.

  1. Under the node /apps create a new node:

    • Name: myBlog
    • Type: nt:folder
  2. Select /apps/myBlog, then using the context menu select Create... followed by Create File.... The dialog that opens allows you to specify:

    • Name: html.jsp

    Click OK. The file is created and opened for edit in the right pane.

  3. Copy the following code to html.jsp, then click Save All:

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 
      pageEncoding="ISO-8859-1"%><%
    %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ TR/html4/loose.dtd"><% 
    %>
    
    <%@page session="false"%>
    <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
    <sling:defineObjects/>
    
    <%@ page import="javax.jcr.Repository,
                       javax.jcr.Session,
                       javax.jcr.SimpleCredentials,
                       javax.jcr.Node,
                       java.net.URLEncoder,
                       java.util.List,
                       java.util.Iterator,
                       javax.jcr.Value,
                       javax.jcr.RepositoryException"%>
    
    <html>
    <head> 
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
      <title><%= currentNode.getProperty("title").getString() %></title> 
    </head> 
    <body> 
      <div>
        <h1><%= currentNode.getProperty("title").getString() %></h1>
        <br>
        <%= currentNode.getProperty("body").getString() %>
      </div>
    </body> 
    </html>
            
  4. From a browser access the node 2010 as html using:

    http://localhost:7402/content/myBlog/2010.html

    The tab name will show the contents of the property title, with the page content showing the contents of both the properties title and body:

    file

    You can also select the other nodes:

    • http://localhost:7402/content/myBlog.html
    • http://localhost:7402/content/myBlog/2010/March.html
    • http://localhost:7402/content/myBlog/2010/March/01March2010.html
    • http://localhost:7402/content/myBlog/2010/March/02March2010.html

    All nodes will be rendered using the same script.

Showing Links to Child Pages

To allow a visitor to navigate through the blog, for each post we can provide links to all child pages.

  1. Replace the contents of html.jsp with the following code; again click Save All:

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 
      pageEncoding="ISO-8859-1"%><%
    %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ TR/html4/loose.dtd"><% 
    %>
    
    <%@page session="false"%>
    <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
    <sling:defineObjects/>
    
    <%@ page import="javax.jcr.Repository,
                       javax.jcr.Session,
                       javax.jcr.SimpleCredentials,
                       javax.jcr.Node,
                       javax.jcr.NodeIterator,
                       java.net.URLEncoder,
                       java.util.List,
                       java.util.Iterator,
                       javax.jcr.Value,
                       javax.jcr.RepositoryException"%>
    
    <html>
    <head> 
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
      <title><%= currentNode.getProperty("title").getString() %></title> 
    </head> 
    <body> 
      <div>
        <h1><%= currentNode.getProperty("title").getString() %></h1>
        <br>
        <%= currentNode.getProperty("body").getString() %>
        <br><br>
        <%
        NodeIterator ni = currentNode.getNodes(); 
    
        while (ni.hasNext()) {
          Node nii = ni.nextNode();
          String printNodePath = nii.getPath(); 
          String printNodeTitle = nii.getProperty("title").getString();
          %>
          <a href="<%= printNodePath %>.html"><%= printNodeTitle %></a>
          <br>
          <%
        }
        %>
      </div>
    </body> 
    </html>
            

    This adds the following to the script:

    • the page imports needed to use node iterators
                       javax.jcr.NodeIterator,
            
    • the instructions to loop through all child nodes and show the title as a link
        <br><br>
        <%
        NodeIterator ni = currentNode.getNodes(); 
    
        while (ni.hasNext()) {
          Node nii = ni.nextNode();
          String printNodePath = nii.getPath(); 
          String printNodeTitle = nii.getProperty("title").getString();
          %>
          <a href="<%= printNodePath %>.html"><%= printNodeTitle %></a>
          <br>
          <%
        }
        %>
            
  2. From a browser access the node 2010 as html, again using:

    http://localhost:7402/content/myBlog/2010.html

    The page will have been updated with links to the child nodes:

    file

    You can also select the other nodes:

    • http://localhost:7402/content/myBlog.html
    • http://localhost:7402/content/myBlog/2010/March.html
    • http://localhost:7402/content/myBlog/2010/March/01March2010.html
    • http://localhost:7402/content/myBlog/2010/March/02March2010.html

    Links to child nodes will be shown where available.

Imposing a Style

Adding, and linking to a CSS file will impose a predefined style across all pages.

  1. Select /apps/myBlog, then using the context menu select Create... followed by Create File.... The dialog that opens allows you to specify:

    • Name: style.css

    Click OK to create the file; it will be opened for edit in the right pane.

  2. Copy the following to style.css then click Save All:

    body { 
        margin-bottom:1px;
        font-family:georgia,times;
        color: red;
    } 
    
    a {
        padding: 5px; 
        color: blue;
    }
    
    a .small {
        padding: 2px;
        border: none;       
    }
    
    div {
        padding:5px; 
    }
    
    h1 {
        font-size: 150%;
        border-bottom: solid grey 1px;  
        color: green;    
    }
            
  3. Add the following line to the <head> section of html.jsp; again click Save All:

      <link rel="stylesheet" href="/apps/myBlog/style.css" type="text/css">
            

    The script will now contain:

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 
      pageEncoding="ISO-8859-1"%><%
    %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ TR/html4/loose.dtd"><% 
    %>
    
    <%@page session="false"%>
    <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
    <sling:defineObjects/>
    
    <%@ page import="javax.jcr.Repository,
                       javax.jcr.Session,
                       javax.jcr.SimpleCredentials,
                       javax.jcr.Node,
                       javax.jcr.NodeIterator,
                       java.net.URLEncoder,
                       java.util.List,
                       java.util.Iterator,
                       javax.jcr.Value,
                       javax.jcr.RepositoryException"%>
    <html>
    <head> 
      <link rel="stylesheet" href="/apps/myBlog/style.css" type="text/css">
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
      <title><%= currentNode.getProperty("title").getString() == null ? "Title" : currentNode.getProperty("title").getString() %></title> 
    </head> 
    <body> 
      <h1><%= currentNode.getProperty("title").getString() == null ? "Title" : currentNode.getProperty("title").getString() %></h1>
      <div  class="body">
        <br>
        <%= currentNode.getProperty("body").getString() == null ? "Body" : currentNode.getProperty("body").getString() %>
        <br><br>
        <%
        NodeIterator ni = currentNode.getNodes(); 
    
        while (ni.hasNext()) {
          Node nii = ni.nextNode();
          String printNodePath = nii.getPath(); 
          String printNodeTitle = nii.getProperty("title").getString();
          %>
          <a href="<%= printNodePath %>.html"><%= printNodeTitle %></a>
          <br>
          <%
        }
        %>
      </div>
    </body> 
    </html>
            
  4. Now when you access the node 2010 from a browser using:

    http://localhost:7402/content/myBlog/2010.html

    The style will have changed, in particular the fonts and colors used:

    file

    You can also select the other nodes:

    • http://localhost:7402/content/myBlog.html
    • http://localhost:7402/content/myBlog/2010/March.html
    • http://localhost:7402/content/myBlog/2010/March/01March2010.html
    • http://localhost:7402/content/myBlog/2010/March/02March2010.html

    The same styles are applied to all pages.

Basic Error Handling

To increase the stability of the rendering script you can introduce some basic error handling:

  • check that the properties exist
  • check that the properties are not null
  1. To test the error handling you can create a new node under /content/myBlog/2010:

    • Name: April
    • Type: nt:unstructured

    Do not create any properties for this node.

  2. Click Save All.

  3. Access the node April from a browser using:

    http://localhost:7402/content/myBlog/2010/April.html

    An error message is seen as the script tries to access properties that do not exist:

    title (500)
    
    The requested URL /content/myBlog/2010/April.html resulted in an error in /apps/myBlog/html.jsp.
    Exception:
    
    javax.jcr.PathNotFoundException: title
    
            
  4. Now replace the entire contents of html.jsp with the following code and click Save All.

    This:

    • Sets default texts, to be used if the properties do not exist.
    • Tests to confirm that the properties title and body do exist.
    • Tests all properties and paths for null; if the value is null a standard text is taken for display.
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 
      pageEncoding="ISO-8859-1"%><%
    %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ TR/html4/loose.dtd"><% 
    %>
    
    <%@page session="false"%>
    <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
    <sling:defineObjects/>
    
    <%@ page import="javax.jcr.Repository,
                       javax.jcr.Session,
                       javax.jcr.SimpleCredentials,
                       javax.jcr.Node,
                       javax.jcr.NodeIterator,
                       java.net.URLEncoder,
                       java.util.List,
                       java.util.Iterator,
                       javax.jcr.Value,
                       javax.jcr.RepositoryException"%>
    
    <html>
    <head> 
      <link rel="stylesheet" href="/apps/myBlog/style.css" type="text/css">
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
      <% 
      String currentNodeTitle = "Title Missing";
      String currentNodeBody = "Body Missing";
      if (currentNode.hasProperty("title")) {
        currentNodeTitle = currentNode.getProperty("title").getString() == null ? "Title Missing" : currentNode.getProperty("title").getString();
      }
      if (currentNode.hasProperty("body")) {
        currentNodeBody = currentNode.getProperty("body").getString() == null ? "Body Missing" : currentNode.getProperty("body").getString();
      }
      %>
      <title><%= currentNodeTitle %></title> 
    </head> 
    <body> 
      <h1><%= currentNodeTitle %></h1>
      <div  class="body">
        <br>
        <%= currentNodeBody %>
        <br><br>
        <%
        NodeIterator ni = currentNode.getNodes(); 
    
        while (ni.hasNext()) {
          Node nii = ni.nextNode();
          String printNodePath = (nii.getPath() == null ? "Path" : nii.getPath());
          String printNodeTitle = "Title missing";
          if (nii.hasProperty("title")) {
            printNodeTitle = nii.getProperty("title").getString() == null ? "Title Missing" : nii.getProperty("title").getString();
          }
          %>
          <a href="<%= printNodePath %>.html"><%= printNodeTitle %></a>
          <br>
          <%
        }
    
        %>
      </div>
    </body> 
    </html>
            
  5. When you now access the node April from a browser using:

    http://localhost:7402/content/myBlog/2010/April.html

    The default texts can be seen for the properties that do not exist on this node:

    file

Adding an Image

  1. Using WebDAV copy a (small) graphic file into /apps/myBlog. Call it myBlog.png.

    file
  2. Insert the following line immediately under the <body> line in the script:

    <a href="/content/myBlog.html"><img src="/apps/myBlog/myBlog.png" width="80px" height="60px" border="0" alt="myBlog" /></a>
    
            
  3. When you access any of the nodes in the browser the image appears. The underlying link will take you back to /content/myBlog.html.

    file

Multiple Renderings of the same Page

As CRX uses Sling, the same principles of URL decomposition and Request Processing apply.

Certain renderings are available as standard with CRX:

XML

The XML format can be accessed with the extension *.xml; for example:

  • http://localhost:7402/content/myBlog/2010.xml

− <_x0032_010 jcr:primaryType="nt:unstructured" body="All entries for 2010." title="2010">
  − <March jcr:primaryType="nt:unstructured" body="All entries for March 2010." title="March 2010">
    <_x0030_1March2010 jcr:primaryType="nt:unstructured" body="Sunny<br>First day of meteorological spring." title="1st March 2010"/>
    <_x0030_2March2010 jcr:primaryType="nt:unstructured" body="Cloudy with sunny spells." title="2nd March 2010"/>
  </March>
  <April jcr:primaryType="nt:unstructured"/>
</_x0032_010>
        
JSON

The JSON format can be accessed with the extension *.json or *.infinity.json; for example:

  • http://localhost:7402/content/myBlog/2010.json
    to show details of the current node only

{"title":"My Blog","body":"Mine, all mine.","jcr:primaryType":"nt:unstructured"}
        

  • http://localhost:7402/content/myBlog/2010.infinity.json
    to show details of the current node and all nodes underneath

{
  "title":"My Blog",
  "body":"Mine, all mine.",
  "jcr:primaryType":"nt:unstructured",
  "2010":{
    "title":"2010",
    "body":"All entries for 2010.",
    "jcr:primaryType":"nt:unstructured",
    "March":{
      "title":"March 2010",
      "body":"All entries for March 2010.",
      "jcr:primaryType":"nt:unstructured",
      "01March2010":{
        "title":"1st March 2010",
        "body":"Sunny<br>First day of meteorological spring.",
        "jcr:primaryType":"nt:unstructured"
      },
      "02March2010":{
        "title":"2nd March 2010",
        "body":"Cloudy with sunny spells.",
        "jcr:primaryType":"nt:unstructured"
      }
    },
    "April":{
      "jcr:primaryType":"nt:unstructured"
    }
  },
  "comment":{
    "name":"me",
    "comment":"my comment.",
    "jcr:primaryType":"nt:unstructured"
  }
}
        

Creating a Customized Rendering

To display a (more easily) printable version of your HTML page you can use the selector print together with the extension html:

http://localhost:7402/content/myBlog/2010.print.html

This will select a script:

  • print.html.jsp - if available
  • html.jsp - if print.html.jsp is not available
  1. Select /apps/myBlog then using the context menu select Create... followed by Create File.... The dialog that opens allows you to specify:

    • Name: print.html.jsp
  2. print.html.jsp will be opened for edit in the right pane. Copy the following code to the new file, then click Save All:

    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" 
      pageEncoding="ISO-8859-1"%><%
    %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ TR/html4/loose.dtd"><% 
    %>
    
    <%@page session="false"%>
    <%@taglib prefix="sling" uri="http://sling.apache.org/taglibs/sling/1.0"%>
    <sling:defineObjects/>
    
    <%@ page import="javax.jcr.Repository,
                       javax.jcr.Session,
                       javax.jcr.SimpleCredentials,
                       javax.jcr.Node,
                       javax.jcr.NodeIterator,
                       java.net.URLEncoder,
                       java.util.List,
                       java.util.Iterator,
                       javax.jcr.Value,
                       javax.jcr.RepositoryException"%>
    
    <html>
    <head> 
      <link rel="stylesheet" href="/apps/myBlog/style.css" type="text/css">
      <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> 
      <% 
      String currentNodeTitle = "Title Missing";
      String currentNodeBody = "Body Missing";
      if (currentNode.hasProperty("title")) {
        currentNodeTitle = currentNode.getProperty("title").getString() == null ? "Title Missing" : currentNode.getProperty("title").getString();
      }
      if (currentNode.hasProperty("body")) {
        currentNodeBody = currentNode.getProperty("body").getString() == null ? "Body Missing" : currentNode.getProperty("body").getString();
      }
      %>
      <title><%= currentNodeTitle %></title> 
    </head> 
    <body> 
      <h1><%= currentNodeTitle %></h1>
      <div  class="body">
        <br>
        <%= currentNodeBody %>
        <br><br>
        <%
        NodeIterator ni = currentNode.getNodes(); 
    
        while (ni.hasNext()) {
          Node nii = ni.nextNode();
          String printNodePath = (nii.getPath() == null ? "Path" : nii.getPath());
          String printNodeTitle = "Title missing";
          if (nii.hasProperty("title")) {
            printNodeTitle = nii.getProperty("title").getString() == null ? "Title Missing" : nii.getProperty("title").getString();
          }
          %>
          <a href="<%= printNodePath %>.html"><%= printNodeTitle %></a>
          <br>
          <%
        }
        %>
        <br><br>
        <form>
          <input type="button" value=" Print this page " onclick="window.print();" />
        </form>
      </div>
    </body> 
    </html>
            
  3. Now you can access the node 2010 from a browser using:

    http://localhost:7402/content/myBlog/2010.print.html

    Adding the print selector to the uri presents you with a slightly different rendering of the page:

    • the image is not displayed
    • a print button is provided at the bottom of the page
    file

    You can also select the other nodes:

    • http://localhost:7402/content/myBlog.print.html
    • http://localhost:7402/content/myBlog/2010/March.print.html
    • http://localhost:7402/content/myBlog/2010/March/01March2010.print.html
    • http://localhost:7402/content/myBlog/2010/March/02March2010.print.html

    The same rendering is applied to all pages.

    Note

    If you delete, or rename, print.html.jsp and reselect http://localhost:7402/content/myBlog/2010.print.html it will be rendered using html.jsp.

Adding a User Comment

Allowing visitors to your site to post information can be achieved with forms.

  1. Select /apps/myBlog, then using the context menu select Create... followed by Create File.... The dialog that opens allows you to specify:

    • Name: comment.html
  2. comment.html will be created and opened for edit in the right pane. Copy the following code to the new file, then click Save All:

    <html>
    <head><title>Simple write example</title>
      <link rel="stylesheet" href="/apps/myBlog/style.css" type="text/css">
    </head>
    <body>
      <h1>Simple Write</h1>
        
      <!-- post your form to the content repository -->
      <form action="/content/myBlog/comment" method="POST">
        <!-- title -->
        <h2>Name</h2>
        <input type="text" name="name" />
    
        <!-- description -->
        <h2>Comment</h2>
        <textarea rows="5" name="comment"></textarea>
            
        <p><input type="submit" value="Submit"></p>
      </form><br>
        
      <div class="note">
        This page does not use any custom client-side or server-side code
        to create content, the above HTML form is sufficient for this. 
      </div>
            
    </body>
    </html>
            
  3. Add the following line to your html.jsp script. Insert it just before the final </div>.

    <br>
    <a href="/apps/myBlog/comment.html">Comment</a>
            
  4. Select a page, for example http://localhost:7402/content/myBlog/2010.html.

    A new link Comment will be shown:

    file
  5. Click on Comment, a new page will open allowing you to submit your name and a comment.

    file
  6. Enter your Name and a Comment then click Submit.

  7. Using CRXDE Lite navigate to /content/myBlog. A new node comment has been created, with two properties name and comment, holding the details you have just entered.

Creating a Web Syndication Feed

A web syndication feed can be added. The following is a very simple example to show the general principles.

To illustrate the use of other scripting languages we will use ESP for this example.

  1. Select /apps/myBlog, then using the context menu select Create... followed by Create File.... The dialog that opens allows you to specify:

    • Name: rss.esp
  2. rss.esp will be created and opened for edit in the right pane. Copy the following code to the new file, then click Save All:

    <?xml version="1.0"?>
    <rss version="2.0">
    <channel>
    <%
    var currentNodeTitle = "Title Missing";
    var currentNodeBody = "Body Missing";
    var currentNodePath = currentNode.getPath();
    if (currentNode.hasProperty("title")) {
      currentNodeTitle = currentNode.getProperty("title").getString();
    }
    if (currentNode.hasProperty("body")) {
      currentNodeBody = currentNode.getProperty("body").getString();
    }
    %>
      <item>
        <title><%= currentNodeTitle %></title>
        <description><%= currentNodeBody %></description>
        <link>http://localhost:7402<%= currentNodePath %>.html</link>
      </item>
    </channel>
    </rss>
            
  3. You can now select the feed for a page using the extension *.rss; for example, http://localhost:7402/content/myBlog/2010.rss:

    file

    This will show:

    • the page title; this also functions as a link to the page content itself
    • the page body content