Apache Jackrabbit : Jsop

Jsop

Overview

"Jsop" is the idea of a lightweight HTTP protocol for manipulating JSON-based object models.

See David Nüscheler's slides for an initial proposal.

This protocol would include

  • a mapping between the JCR data model and JSON
  • a notation to identify object members (this will be very similar to JCR path notation)
  • a way to expose information about a tree of JCR nodes using JSON notation; if this needs to co-exist with the classical view (aka WebDAV), we either need a creative way to mint new URIs, or may have to try content negotiation
  • one or more formats expression changes in a JSON structure

JCR-JSON mapping

TBD.

Identifier Notation

TBD (I believe raw JCR paths work as they subset JSON names and never need the "/"; but what about namespace prefixes? The current use is compact but doesn't necessarily yield stable identifiers )

IETF Work on Identifier Notation

Internet Draft:

  • a pointer syntax for identifying objects in an object tree: http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer
  • note that this uses "/" as separator and escapes "/" and "~" as "~1" and "~0"
  • furthermore note that it uses "arrayname/N" to address entry N of an array; I don't think we have similar functionality in JSOP

HTTP binding

It needs to be defined how JCR nodes and JCR events are mapped to HTTP URIs; this includes the name mapping, the granularity, and more.

For instance:

  • handling of workspace name
  • escaping non-URI characters
  • do nodes and properties need to be distinguished
  • namespace prefix handling
  • co-existence with other protocols, such as WebDAV
  • how to expose ordered collections (JavaScript object membership is not ordered)

TODO: describe the current implementation in jcr-server

Diff Formats

IETF Work on Diff Formats

Internet Draft:

Open Issues:

  • the format does not define a place for metadata

This issue has been raised as a potential enhancement on the IETF apps-discuss mailing list.

Draft Implementations: JSOP-Diff

The definitions below are based on the format used by JCR Server but diverge in some areas. This is still work in progress and definitions may change at anytime.

Compact Syntax

// JSOP-Diff Proposal
DIFFS     ::= (ADD | SET | REMOVE | MOVE | COPY | TEST | METADATA | EXTENSION)*
ADD       ::= "+" STRING ":" OBJECT
SET       ::= "^" STRING ":" ATOM | ARRAY
REMOVE    ::= "-" STRING
MOVE      ::= ">" STRING ":" STRING
COPY      ::= "*" STRING ":" STRING
TEST      ::= "=" STRING ":" ATOM | ARRAY
METADATA  ::= "@" OBJECT
EXTENSION ::= OP STRING ":" (OBJECT | ATOM | ARRAY)
OP        ::= /* any single character except for +, ^, -, >, *, =, @ */

// JSON (RFC 4627)
OBJECT   ::= "{" (PAIR ("," PAIR)*)? "}"
PAIR     ::= STRING ":" VALUE
VALUE    ::= COMPOUND | ATOM
COMPOUND ::= OBJECT | ARRAY
ATOM     ::= STRING | NUMBER | "true" | "false" | "null"
ARRAY    ::= [ (VALUE ("," VALUE)*)? ]

STRING   ::= /* See RFC 4627, Section 2.5 */
NUMBER   ::= /* See RFC 4627, Section 2.4 */

IETF ABNF variant:

diffs =   *( ws ( add / set / remove / move / copy / test ) ws )

add =     "+" ws pointer ws ":" ws object
copy =    "*" ws pointer ws ":" ws pointer
move =    ">" ws pointer ws ":" ws pointer
remove =  "-" ws pointer
set =     "^" ws pointer ws ":" ws ( atom / array ) ; object?
test =    "=" ws pointer ws ":" ws ( atom / array ) ; object?

atom =    string / number / false / null / true

pointer = string

; JSON
array =   <see RFC4627, Section 2.3>
false =   <see RFC4627, Section 2.1>
null =    <see RFC4627, Section 2.1>
number =  <see RFC4627, Section 2.4>
object =  <see RFC4627, Section 2.2>
string =  <see RFC4627, Section 2.5>
true =    <see RFC4627, Section 2.1>
ws =      <see RFC4627, Section 2.1>

A parser, and a simple test case for this syntax is available from the sandbox.

Also available are a tokenizer, a builder, and a Jsop writer / reader. Those implementations are token based, and therefore not limited to the JSOP format described here.

Syntax

jsop:

  • diff
  • diff jsop

A Jsop string contains one or multiple Jsop diff lines.

diff:

  • addNodeDiff
  • setPropertyDiff
  • removeNodeDiff
  • removePropertyDiff
  • moveNodeDiff
  • copyNodeDiff
  • testProperty
  • metaData

A diff line can contain the information about adding nodes (possibly multiple nested nodes), adding a property to a node, setting a property, moving a node, or removing a node or property. There is a special metadata diff line.

addNodeDiff:

  • + pathString: object

The added node may contain child nodes.

addPropertyDiff:

  • + pathString: propertyValue

setPropertyDiff:

  • ^ pathString: propertyValue

Modifies the value of an existing property or otherwise creates a property with the specified value.

moveNodeDiff:

  • > pathString: newPathString

copyNodeDiff:

  • * pathString: newPathString

removeNodeDiff:

  • - pathString

removePropertyDiff:

  • ^ pathString: null

Setting the value to null will remove the property.

propertyValue:

  • string
  • number
  • array
  • true
  • false

A property value can be any value, except for a object itself.

testProperty:

  • = pathString: { propertyValue | null }

Before applying the rest of patch, the value is verified. If it does not match, then the subsequent line(s) will not be applied. The exact semantics are not yet defined however and will most likely be implementation specific - for example it is undefined whether a mismatch will result in an exception or not, and whether all following lines of the commit belong to the same atomic operation or not. This addition allows to construct atomic commits.

metaData:

  • @ object

The metadata line contains metadata about the following diff lines. Metadata typically includes the timestamp (when did the change occur), the user, the commit message. A jsop object can contain multiple metadata lines. It depends on the implementation whether or not metadata is used, and how it is used.

object:

  • {}
  • { members }

members:

  • pair
  • pair, members

pair:

  • string: value

array:

  • []

  • [elements ]

elements:

  • value
  • value, elements

value:

  • string
  • number
  • object
  • array
  • true
  • false
  • null