Exploring CRX

You are reading the CRX 2.3 version of Exploring CRX.
This documentation is also available for the following versions: CRX 2.2  CRX 2.1 

CRX is a data storage system specifically designed for content-centric applications. CRX implements the Content Repository API for Java Technology (JCR). This standard defines a data model and application programming interface (that is, a set of commands) for content repositories. A JCR repository can be thought of as a "super file system". It combines characteristics of conventional file systems with those of relational databases, and adds a number of additional features that content applications often need.

What is JCR?

A content repository, as defined by JCR, combines features of the traditional relational database with those of a conventional file system.

File system-like features supported by JCR include:

  • Hierarchy: Content in a JCR repository can be addressed by path. This is useful when delivering content to the web since most websites are also organized hierarchically.
  • Semi-structured content: JCR can store structured documents, like XML, either as opaque files (as a file system would) or as structures ingested directly into the JCR hierarchy.
  • Access Control and Locking: JCR can restrict access to different parts of the content hierarchy based on policies or ACLs. It also supports locking of content to prevent conflicts.

Database-like features supported by JCR include:

  • Query Access: JCR supports querying with languages such as SQL.
  • Structured Content: JCR can enforce constraints on data structures according to schema.
  • Referential Integrity: JCR can enforce referential integrity between content items.
  • Transactions: Interactions with a JCR repository can be bracketed in transactions and rolled back when needed.

In addition, JCR provides the following services that content-centric applicaitons often need, but that neither file systems nor databases typically provide:

  • Unstructured Content: JCR can also support arbitrary dynamic data structures without schema constraints.
  • Full-text search: JCR supports full-text search of content.
  • Sort order: Items within the hierarchy can maintain their ordering, if desired.
  • Observation: API clients can register listeners to react to changes made to the repository.
  • Versioning: JCR supports an advanced versioning system for repository content.

For more information, see the JCR specification (in HTML).

JCR Repository Model

Inside a JCR repository, content is organized into one or more workspaces, each of which holds of a hierarchical structure of nodes and properties.

Beginning with the root node at the top, the hierarchy descends much like the directory structure of a file system: each node can have zero or more child nodes and zero or more properties. Properties cannot have children but do have values.

The values of properties are where the actual pieces of data are stored. These can be of different types: strings, dates, numbers, binaries and so forth. The structure of nodes above the properties serves to organize this data according to whatever principles are employed by the application using the repository. Here is a schematic showing a workspace with a simple tree of nodes and properties:

file

This diagram depicts the content of a workspace W0 in repository R.

Paths and Identifiers

Every node and property in the workspace has a name and every node has an identifier. The names allow each node and property to be addressed by path, much like in a file system. For example, above, the property /A/D has as its value the string "Once upon a time..." and the node /A/E has property I which holds a binary property.

The identifier of a node has to be unique within the workspace, so that each node can also be addressed directly by its identifier. For example, above, the node /A/E has the identifier 0004.

An Example Workspace in CRX

The picture above is greatly simplified, to see a more realistic example, you can examine the repository in your local CRX installation. Assuming you have administrator access, simply go to the CRX Launchpad page and click the link CRXDE Lite (http://localhost:7402/crx/de/ in a default installation). This opens the web-based development environment for CRX.

file

In the top right you will see the username and workspace that you are logged into:

file

On the left side the node hierarchy of the workspace is displayed. The node highlighted in the picture below is /apps/firststeps/0_hello.html:

file

On the bottom of the screen the properties of the node /apps/firststeps/0_hello.html are shown:

file

Property Types

Notice in the picture above that each of the three properties has a type. In the above example there are three properties jcr:created, jcr:createdBy and jcr:primaryType of types DATE, STRING and NAME, respectively. In fact, there are twelve possible property types in JCR:

  • STRING: A piece of text.
  • URI: A universal resource identifier.
  • BOOLEAN: A boolean value (true or false).
  • DATE: A calender date and/or time.
  • LONG: An integer number.
  • DOUBLE: A floating point number.
  • DECIMAL: An arbitrary-precision signed decimal number.
  • PATH: A path to a node or property.
  • NAME: The name of a node, property or other JCR entity.
  • BINARY: Raw binary data.
  • REFERENCE: A reference to another node in the workspace by identifier, that does not permit the removal of the target (it enforces referential integrity).
  • WEAKREFERENCE: A reference to another node in the workspace by identifier, that does permit the removal of the target (it does not enforces referential integrity).

Node Types

Just as properties have types, so do nodes. Looking again at the list of properties of the node
/apps/firststeps/0_hello.html, above, you will see that one of the properties is jcr:primaryType of type NAME. This property is one of a number of special properties that every node automatically has. In this case the property records the name of the node's type: nt:file.

Every node has a node type that defines what subnodes and properties it can have. Above, the type nt:file indicates that the node /apps/firststeps/0_hello.html represents a File object.

Example Node Types in CRX

To see the node types registered in your CRX instance you can point your browser to the the CRX main console:

http://<your-crx>/crx/index.jsp

For example, in the default installation on your local machine this would be:

http://localhost:7402/crx/index.jsp

(note that you will need administrator access)

The main console page will appear:

file

Click the Log In link and log in as an administrator (by default the login is admin and the password is admin). Then click on Node Type Administration. This will take you to a console that shows all the regsitered node types in your CRX instance. Scroll down until you see nt:file in the left pane and click on it. This will reveal the defintion of that node type:

file

For the time being we don't need to go into all the details of this node type definition. The main things to notice are the two subsections entitled Child Node Definitions and Property Definitions. These list the child nodes and properties that a node of type nt:file is permitted (or required) to have.

Looking first at the Property Definitions, we see that four properties are listed: jcr:created, jcr:createdBy, jcr:mixinTypes and jcr:primaryType. A few things to notice:

  • The names of the properties are grayed-out. This indicates that they have been inherited from the defintions of supertypes of nt:file. and are not defined in nt:file itself. This demonstrates an important feature: Node types support inheritance.
  • The Column called Man indicates whther a property or subnode is mandatory. In the case of the properties listed, only jcr:primaryType is mandatory. That means that every node of type nt:file must have a property jcr:primaryType (in fact, every node is required to have this property). The other properties are not mandatory, meaning that a node of type nt:file may have these properties. This demonstrates another feature: Node types can enforce structure.

In the Child Node Definitions we see one entry: jcr:content. The jcr:content entry indicates that a subnode called jcr:content is permitted and that that node must be of type nt:base. Additional allowed child node definitions could be listed here, and an entry with a * (asterisk) as name, would indicate that any other subnodes may also be added with any types. The main thing to notice here is:

  • The * entry indicates that there are no restrictions on subnodes being added to nodes of type nt:file. This demonstartes another principle of JCR: Node types don't always enforce structure, they can also permit unstructured content.

Summary of the JCR Repository Model

The main features of the JCR repository model are:

  • A repository consist of one or more workspaces.
  • Each workspace consists of a hierarchy of nodes and properties.
  • Nodes and properties can be addressed by path.
  • Nodes can also be addressed directly by unique identifiers.
  • Properties store the actual content of the repository.
  • Nodes provide the strucural organization of the content.
  • Properties have types.
  • Nodes have types
  • A node's type governs which properties and subnodes it may or must have.
  • Node types can be used to enforce constarints on content structures.
  • But, JCR also supports free-form unstructured content.

Download and Start Working

This section gets you up and running with CRX quickly.

Download CRX

CRX comes in a few product editions to match your usage and deployment needs. Please visit the CRX page on day.com to decide, which CRX edition is right for you.

To download CRX for production use, visit the Daycare website and click Download CRX.

To download the CRX Developer Edition, which is free to use for all non-production purposes, visit the CRX Developer download page.

Installing, Starting, and Stopping CRX

This section describes how to install, start, and stop CRX instances. For troubleshooting tips during installation, see Troubleshooting.

Installing CRX

To install CRX:

  1. Copy the CRX quickstart jar file (crx-<version>-<edition>.jar) to the desired directory on the host file system.

    Caution

    Only US-ASCII characters are allowed in the name of the folder used to store the Quickstart jar (or any other runnable jar).

  2. Copy a valid license.properties file into the same directory as the quickstart jar file.

    Note

    Note: If when starting the application, you do not provide the license.properties file, CRX asks you for a valid license key. You can request a valid license key from Day at this time.

  3. Start CRX Quickstart for the first time.

    • When CRX is started for the first time, it will automatically create a crx-quickstart folder in the same directory as the quickstart jar file. 
    • Inside the crx-quickstart directory, CRX will place its working files and create a fresh repository.

    Due to this initialization process, the first startup will take longer than subsequent startups. See Starting CRX for detailed instructions on how to start CRX Quickstart.

Starting CRX

In order to start CRX, simply double-click CRX Quickstart or start CRX from the command line or a custom script.

To start CRX:

  1. Navigate to the quickstart jar file (crx-<version>-<edition>.jar), either in your GUI file-system window or in a terminal, using the command line.

  2. Do one of the following:

    • If using a GUI (for example, Windows Explorer or MAC Finder), double-click the quickstart jar file (crx-<version>-<edition>.jar).
    • If using the command line, enter the java command using the following principle:
      with a 32bit VM:
          java -Xmx384M -jar crx-<version>-<edition>.jar
      or, with a 64bit VM
          java -XX:MaxPermSize=128m -Xmx512M -jar crx-<version>-<edition>.jar
      CRX is ready when the message "Press CTRL-C to shutdown the Quickstart server..." is seen.

    Note

    By default, CRX will automatically open a browser window on startup. When starting CRX from the command line on a remote server, you may want to suppress this by adding the -nobrowser option to the above command line.

  3. In order to automate the startup of CRX, you can use a startup script.

    When CRX is started the first time, it places example startup scripts in the crx-quickstart/server folder. The start and stop scripts are for UNIX, Linux and Macintosh, the server.bat script is for Windows.

Note

See Configuring JVM Settings for CRX if you need to change some of the advanced JVM settings for CRX (such as JVM memory size).

CRX starts and automatically opens the appropriate page in your web browser. Once started, you have access to CRX. See the CRX User Guide for details on using CRX.

file

Showing Startup Statistics

The CRX Quickstart window shows the startup time:

file

This also forms a link to startup statistics of the individual elements:

file

Stopping CRX

To stop CRX, do one of the following:

  • If you started CRX from the command line, press Ctrl+C to shut down the server.
  • If you started CRX with the start script, now use the stop script.
  • If you started CRX by double-clicking on the jar file, click on the On button in the Quickstart window. This will change to Off as the server shuts down.

Getting around in CRX

This guide tells you how to manage and use the CRX repository through the Web-based tools.

CRX Launchpad

CRX Launchpad is an enhanced welcome screen and repository dashboard, providing access to the most frequently used repository functions. Additionally, it enables users to work with the repository content directly from desktop via WebDAV integration and to find content easily through search screen.

To access the CRX Launchpad, type the path you specified when installing CRX, such as:

http://www.myCompany.com:4502/libs/crx/core/content/welcome.html
http://localhost:4502/libs/crx/core/content/welcome.html


        
file
From the CRX Launchpad, you can perform a number of activities, including using your content, developing with CRX, and managing the content repository.
CRXDE Lite
Develop applications with a web-based IDE.
Packages 
Package and share applications.
Package Share Download applications from Adobe and the community.
Security Manage users and groups.
Clustering
Manage clustered deployements.
Backup
Carry out backup tasks.

Searching Repository Content

To search for content stored within the repository:

  1. In the CRX Launchpad, click CRXDE LITE. The search field will be available in the middle of the page.

  2. Type a query and click Search. CRX returns any relevant content from the repository with the search terms highlighted.

Note

If CRX does not return excerpts or highlight search terms, these features have not been enabled. See Excerpt Creation and Highlighting.

file

Developing on CRX

Note

This information is intended as an introduction to developing with CRX and assumes previous experience in development.

Tools and Mechanisms for Development

There are several tools and mechanisms available for developing within CRX, including:

  • CRXDE Lite is embedded in CRX and enables you to perform standard development tasks in the browser. See Developing with CRXDE Lite for an introduction.
  • CRXDE is the Eclipse based version, a standalone product that works with CRX and offers additional functionality; for example, debugging and code-completion. See Developing with CRXDE.
  • WEBDAV lets you display and edit the contents of the repository as a file system. See Webdav Access for more information.

The  introductory example Developing a Simple Blog uses CRXDE Lite, and will introduce certain basic tasks as well.

Developing a Simple Blog

Learning by doing is often an efficient method - here a very simple example highlights some central issues and is followed by more detailed information (and links) about the concepts.

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:4502/

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

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 / in the repository.

  2. Select / 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: content
    • Type: select sling:OrderedFolder
  3. Create a new node, as before, under /content and specify:

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

  5. Select the new node myBlog.

  6. 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.

  7. 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.

  8. 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.

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. For every nodes created under /content, add a new property :

    • Name: sling:resourceType
    • Type: String
    • Value: myBlog

    We have to define the sling:resourceType property on nodes in order to define the render script. The script will be taken from /apps/myBlog automatically as explained in the Location Script section.

  5. From a browser access the node 2010 as html using:

    http://localhost:4502/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:4502/content/myBlog.html
    • http://localhost:4502/content/myBlog/2010/March.html
    • http://localhost:4502/content/myBlog/2010/March/01March2010.html
    • http://localhost:4502/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:4502/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:4502/content/myBlog.html
    • http://localhost:4502/content/myBlog/2010/March.html
    • http://localhost:4502/content/myBlog/2010/March/01March2010.html
    • http://localhost:4502/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:4502/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:4502/content/myBlog.html
    • http://localhost:4502/content/myBlog/2010/March.html
    • http://localhost:4502/content/myBlog/2010/March/01March2010.html
    • http://localhost:4502/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:4502/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:4502/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

Note

You can find more information on how to use WebDAV in the WebDAV Access section.

  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 and then click Save All:

    <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. For example http://localhost:4502/content/myBlog/2010.html

    file

    The link underlying the image will take you back to /content/myBlog.html.

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:4502/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:4502/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:4502/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:4502/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:4502/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:4502/content/myBlog.print.html
    • http://localhost:4502/content/myBlog/2010/March.print.html
    • http://localhost:4502/content/myBlog/2010/March/01March2010.print.html
    • http://localhost:4502/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:4502/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:4502/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:4502<%= currentNodePath %>.html</link>
      </item>
    </channel>
    </rss>
            
  3. You can now select the feed for a page using the extension *.rss; for example, http://localhost:4502/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

Access Control

Access Control for developers is covered under Access Rights.

Additionally you can read how access rights are administered in CRX - together with user and group accounts.

A Jackrabbit based document management system with dynamic ACLs is also discussed under The ACL is Dead.

Node Types

As CRX is a JCR repository, node types are fully documented under 3.7 Node Types of the JCR 2.0 specification.

WebDAV

WebDAV access gives you direct access to the content repository through your desktop. You can access the contents of the respository as with a standard file-system, using an Explorer or Finder window.

Files dropped into the repository through the WebDAV connection are automatically full-text indexed and can be searched with the standard search interfaces through the standard Java APIs.

OSGi and Sling

OSGi

OSGi is a fundamental element in the technology stack of CRX. It is used to control the composite bundles of CRX and their configuration.

OSGi "provides the standardized primitives that allow applications to be constructed from small, reusable and collaborative components. These components can be composed into an application and deployed".

OSGI for beginners also provides an introduction to the general concepts, while OSGi at dev.day covers many aspects.

For CRX this allows easy management of bundles as they can be stopped, installed, started individually. The interdependencies are handled automatically. Each OSGi Component (see the OSGi Specification) is contained in one of the various bundles. For CRX you can manage the configuration settings for such bundles by either:

  • configuring content-nodes in the repository (recommended).
  • using the Apache Felix Web Console.

The CQ documentation covers OSGi configuration, again these principles can be applied to CRX and its bundles.

Sling

CRX is built using Sling, a Web application framework based on REST principles that provides easy development of content-oriented applications. Sling is based upon OSGi and uses a JCR repository, such as Apache Jackrabbit, or Day's CRX, as its data store.

  • Sling Request Processing is covered in the CQ documentation - these general principles are the same and can be applied to CRX too.
  • dev.day covers many Sling details of interest to a developer.
  • Apache Con also archives various presentations including:
    • Embrace OSGi - A Developer's Quickstart
    • Rapid JCR applications development with Sling

Creating Bundles

As Sling is based upon OSGi, bundles are an integral concept.

The following locations contain information and examples about creating and deploying bundles:

Third Party Libraries

Custom CQ5 Workflow that integrates Twitter and Jabber illustrates an example of working with third party libraries.

Observation Listeners

File Uploads in Sling (JCR EventListeners) illustrates observation listeners.

Schedulers

The Apache Sling Scheduler enables you to easily schedule jobs within your application. Jobs can be executed at a specific time, regularly at a given period or at the time given by a cron expression by leveraging the Sling scheduler service. 

A coding example is also given on dev.day.

Setting up Services

Summary of Information Sources...

Some have been referenced above, but the following are all valuable sources of information: