Defining Content

Content in the JCR is by nature defined in a highly-structured format, meaning that individual classes and properties are identified. In object-oriented modeling, structure is expressed via the definition of classes that can be visualized in a UML class diagram. Classes contain member variables and methods and can be instantiated as object. The JCR follows a very similar approach, except that these concepts are named differently:

OO-Concept

JCR Equivalent

Description

Class

Node Type

Defines the structure of the objects to be created.

Object

Node

Instance of a node type.

Member Variable

Property

The JCR uses primitive types to define properties, much like standard object-oriented programming which uses primitives such as integers and strings also.

Type

Property Type

Defines atomic types, such as integers, strings, dates, and pointers (references).

Function

None

The JCR does not model functionality, only data. Hence there is no equivalent of a function.

The JCR further defines a common parent type for nodes and properties, called item. Each workspace in a JCR repository contains any number of items.

A node may reference any number of child nodes as well as any number of property nodes, essentially utilizing the object-oriented composite pattern to build a graph of items where nodes may be internal or leaf elements and properties may only be leaf elements. Each node must have a parent node, meaning there cannot be free-floating, and hence inaccessible, nodes in the repository.

Items, Nodes, Properties

Items, Nodes, Properties

Let’s take a step back and look at this from the birds-eye perspective. The JCR is essentially a flexible storage engine. It uses a schema definition to describe the allowed structure of the individual instances of nodes and properties. As a matter of fact, this schema definition can be provided as a file. It then provides a programmatic API for the developer to create, store, retrieve, and query content within this structure. The biggest leap from traditional object-oriented programming is that the structure is not defined in terms of class definition but as a schema definition file, most likely in written in XML. This schema definition is also referred to as the content model.

Birds-Eye View of JCR

Birds-Eye View of JCR

In the JCR, the model is expressed through the concept of node types and property types. Every node must have exactly one node type associated with it. The node type defines the properties each node may reference as well as other characteristics of the node. Nodes can be placed in an inheritance relationship, i.e. the node characteristics include the parent type which properties are inherited from. A node type may also be defined to be abstract (in JSR 283 only), meaning that it cannot be instantiated, i.e. no node instances of this type can be created – it is purely used to implement the object-oriented principle of abstraction.

Nodes may have unique identifiers (a UUID) if they inherit from the built-in base type mix:referenceable. This is, in essence, identical to an object’s identity in standard object-oriented programming languages. As a matter of fact, Reference properties in the JCR simply reference the UUID of a node, meaning that a node may be copied, moved, or renamed without breaking these references. As a consequence, all nodes which may be referenced through such a property must inherit from mix:referenceable. Inheriting from this base type automatically injects a property with the name jcr:uuid into the node type declaration. The method Node.getUUID() is consequently merely a shortcut for Node.getProperty(“jcr:uuid “).getValue().getString().

The JCR defines a pre-set number of property types which are split into two major categories: primitive properties, such as integers and strings, and reference properties which may reference other items in the repository or external URIs. Reference types may enforce the concept of referential integrity, i.e. not break links. This is particularly useful for modeling references of content which is contained within one repository. The content editor may rename, move, delete content and the repository automatically enforces that no references break through these actions. There are numerous trade-offs to be considered when choosing these types which are elaborated in the upcoming chapter on content modeling.

Properties may further be defined to be mandatory or optional.

Property Type

Type

Summary

String

Primitive

A string property

Binary

Primitive

A binary large object, or blob. This type is used for storing unstructured data in the repository. Examples include images, css files, flash files, etc.

Date

Primitive

A date property

Long

Primitive

A long property (64-bit signed two’s complement integer)

Double

Primitive

A double property (64-bit IEEE 754 floating point)

Boolean

Primitive

A boolean property (true/false)

Decimal*

Primitive

Arbitrary length decimal number (maps to java.math.BigDecimal)

Name

Primitive

Namespace-qualified string, such as the name of a node type, e.g. as nt:folder or samples:teaser. This can be particularly useful if a property references a content type, such as “all nodes of type samples:teaser in a particular folder.

Path

Reference

Represents a path within the workspace to a particular item (such as /a/b/foo). This reference property does not enforce referential integrity.

Reference

Reference

A reference property refers to another node in the workspace via the id of the referenced node. The repository will enforce referential integrity.

WeakReference*

Reference

Identical to a Reference property with the exception that referential integrity it not enforced. Accessing a “stale” link will throw an exception.

URI*

Reference

Identical to a String property except that it only allows values that conform to the URL syntax (RFC 3986). This is predominantly used for modeling external references, such as web sites.

Undefined

n/a

A property of undefined type. The type can be defined at runtime, meaning by the Node.addNode function. Two node instances of the same node type could hence have the same property (by name) with different types.

Internally, the JCR stores undefined properties as String values, i.e. they are automatically converted. Implementation-specific issues may arise as a consequence when, for example, storing binary properties in undefined properties.

*Denotes JSR-283 specific properties

Properties may further be defined to be multi-valued. This is equivalent to defining an array property, i.e. a property that may have more than one value. It is possible to query the node type definition within the API to determine, for example, whether a property is multi-valued as the following example code illustrates:

Node node = session.getNodeByUUID("some existing uuid");
Property property = node.getProperty("sampleProperty");
if (property.getDefinition().isMultiple()) {
    // there are potentially multiple values
Value[] values = property.getValues();
} else {
    // there is only one value
Value value = property.getValue();
}

Also refer to the CND in a nutshell which outlines the compact node type definition language in-depth.


Namespaces

The repository features native support for namespaces. These namespaces are modeled after XML namespaces and allow different aspects of the content model to be grouped together within them. Namespaces are delimited by a “:” (colon) character. Similar to XML namespaces, the namespace prefix on the left side of the colon is a shorthand notation for the full namespace name, designated by a URI. The JCR defines four built-in namespaces:

Prefix URI Summary
Jcr http://www.jcp.org/jcr/1.0 Reserved for built-in node types and properties, for example the jcr:uuid property.
nt http://www.jcp.org/jcr/nt/1.0 Reserved for built-in primary node types, for example nt:file.
mix http://www.jcp.org/jcr/mix/1.0 Reserved for built-in mixin types, for example mix:referenceable.
xml http://www.w3.org/XML/1998/namespace Reserved for reasons of compatibility with XML. According to the JSR specification, this prefix should not be used by clients of the API in the names of normal nodes or properties, since doing so will cause problems on export to XML.
(empty) (empty) The empty namespace is the default namespace.

In a writeable repository, namespaces can be added via the javax.jcr.NameSpaceRegistry class. The following code registers the samples prefix to the URI http://www.jtoppe.com/samples. Subsequent API calls can now use the samples prefix.

Workspace ws = session.getWorkspace();
// register the samples prefix with the given URI
ws.getNamespaceRegistry().registerNamespace("samples",
                                 "http://www.jtoppe.com/samples");
// use the samples prefix
Node folder = session.getRootNode().addNode("demo", "samples:folder");

Namespaces have to be declared in the repository before they can be referenced through the API or within the node type definition files.

The same hold for the node definition filein which the prefixes used need to be mapped to the URI. Notice that the URI, as the fully qualified identifier, specified in the CND file must match the URI registered via the NameSpaceRegistry.

// CND namespace definitions

Pages: 1 2 3 4 5 6 7 8 9 10 11