Qworum core specification, version 1.0

Abstract

Qworum is a system of interlinked and interactive web-based services.

Qworum defines a new type of web link (the service call link, or "service link"), a new mechanism for state storage, JavaScript and HTML bindings, as well as a new message format.

The World Wide Web is increasingly being used for providing applications, rather than content. A standard mechanism for modularizing web applications would, arguably, significantly increase developer productiviy and facilitate application connectivity. Qworum addresses that need.

Table of contents
  1. Introduction
    1. Purpose
    2. Requirements
  2. Service composition
    1. Multi-phase service calls
    2. Special case: the World Wide Web
    3. Special case: RPC
    4. The user agent as mediator for service calls
  3. Messages
    1. Message format
    2. The http://qworum.net/ XML namespace
    3. The application/xml media type
    4. The .xml and .qrm file extensions
    5. Message evaluation by the user agent
  4. Statements
    1. The call statement
    2. The data statement
    3. The fault statement
    4. The goto statement
    5. The if statement
    6. The nil statement
    7. The return statement
    8. The select statement
    9. The sequence statement
    10. The transform statement
    11. The transient statement
    12. The try statement
    13. The variable statement
  5. Implementations
    1. The qworum JavaScript object
      1. The qworum.features object
      2. The qworum.eval() function
      3. The qworum.set() and qworum.get() functions
      4. The qworum.config object
      5. The qworum.my object
    2. HTML-based linking
      1. The data-qworumc HTML attribute
      2. The data-qworum HTML attribute
    3. Synchronisation
    4. Target frame
    5. Referrer
    6. Bookmarking
  6. Appendices
    1. References
    2. Revision history
    3. Copyright and disclaimer

1. Introduction

1.1. Purpose

The World Wide Web is a system of interlinked hypertext documents accessed via the Internet. Although its initial purpose was to provide an infrastructure for information, the World Wide Web is increasingly being used for applications, which arguably have additional infrastructure needs.

In this context, Qworum defines a standard for decomposing web applications into reusable services. The services that make up a web application do not need to reside all on one single server. With Qworum, the barriers that exist between websites are largely overcome, so that websites can provide services to each other much more easily. In particular, websites can provide interactive services that seamlessly integrate into other websites.

For service providers, the advantage of using Qworum is that services can be interactive as a regular website, or non-interactive as a remote procedure call. In fact, the same service may be interactive during one call, and non-interactive during the next one. In other words, Qworum unifies the World Wide Web and remote procedure call concepts.

Qworum makes use of a specific web message format, which offers functionality that is orthogonal to that of existing web formats such as HTML. As a result, the Qworum specification is expected to evolve independently from those standards.

The present specification provides relevant information for the following groups:

1.2. Requirements

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 [Keywords].

2. Service composition

Qworum is based on the concept of multi-phase services. The service composition mechanism used by Qworum is directly derived from this concept, and explains the design choices made by Qworum. This and related concepts are described below.

The term phase refers to the following three consecutive steps:

  1. a user agent sends a request to a server,
  2. the server performs an operation based on the request and produces a response,
  3. the user agent receives the response from the server.
A phase

According to this definition, conventional remote procedure calls (based on XML-RPC for instance) always consist of a single phase.

The term service refers to a software functionality available on a computer, and used by programs on other computers through network connections. In the context of Qworum, a service is available at a URL that has an http or https scheme, and services are identified by their URL.

2.1. Multi-phase service calls

The term multi-phase service refers to a service whose calls consist of one or more phases.

A multi-phase service call may span several servers, and terminates when the user agent receives a response containing a result message.

In order to continue the current call, a phase may return a response that does not contain a result message. In this case, the user agent will try to use the message for initiating the next phase of the current call. When the HTTP protocol is used, HTTP redirections and interaction messages such as HTML pages allow such call continuations. Another way of performing call continuations is through the use of composition messages.

A multi-phase service call consisting of three phases, using the HTTP protocol

2.2. Special case: the World Wide Web

The multi-phase service call concept is more general than the World Wide Web paradigm.

Indeed, a web browsing session inside a browser tab (or window) is equivalent to a multi-phase service call which never returns a result, and which never calls other services by using the proposed composition mechanism.

2.3. Special case: RPC

The multi-phase service call concept is also more general than the concept of remote procedure call: a multi-phase service call consisting of a single phase is equivalent to a conventional remote procedure call.

2.4. The user agent as mediator for service calls

According to the proposed composition mechanism, a service calls another service as follows:

  1. The calling service sends a composition message to the user agent.
  2. Based on the instructions contained in this message, the user agent then performs the service call, between two consecutive phases of the calling service.
  3. The service call terminates when one of its phases sends a result message to the user agent.
  4. The user agent then sends the received result to the calling service, at a URL specified in the composition message previously received.
Service composition: a service on a first server calls a service on a second server

Qworum does not impose any restrictions on the number of nested calls: a service may call another service, which calls another service, which calls yet another service, etc. A service may also make recursive calls to itself.

3. Messages

3.1. Message format

Qworum defines an XML [XML] message format that supports the basic service composition pattern described in the previous section.

Qworum messages are scripts, rather than human-centric documents. Each Qworum message MUST contain one Qworum statement, which MUST NOT be the data statement.

Here is a result message that might be sent back by an e-mail lookup service:

<!-- message contains a 'return' statement -->
<qrm:return xmlns:qrm='http://qworum.net/'>
  <email>john.smith@email.com</email>
</qrm:return>

And here is a composition message used for calling the e-mail lookup service (goto describes the next phase of the current call, and call describes the service call to be performed by the user agent on behalf of the current call):

<qrm:goto href='receive_email_address' xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name> <!-- call parameter -->
  </qrm:call>
</qrm:goto>

Qworum messages also enable more advanced usage patterns. Here is a message which is neither a pure result message, nor a composition message (this particular message might be described as a result message with parts provided by service calls):

<qrm:return xmlns:qrm='http://qworum.net/'>
  <emails>
    <qrm:call href='email_lookup'>
      <name>John Smith</name>
    </qrm:call>
    <qrm:call href='email_lookup'>
      <name>Jack Smith</name>
    </qrm:call>
  </emails>
</qrm:return>

3.2. The http://qworum.net/ XML namespace

Qworum defines an XML vocabulary that is used in messages. All elements of this vocabulary belong to the http://qworum.net/ namespace [XMLnamespaces]. Elements belonging to this namespace are also referred to as Qworum elements. Elements that do not belong to this namespace are also referred to as non-Qworum elements.

All statements are described by a Qworum element, except the data statement. Some Qworum elements, namely title and catch, do not describe a statement but are part of an enclosing statement.

3.3. The application/xml media type

The media type of Qworum messages is application/xml. Media types are explained in the section 3.7 of the HTTP/1.1 specification [HTTP/1.1].

User agents which implement the present version of the Qworum specification SHOULD include this media type in the Accept headers of the HTTP(S) requests they generate: For example, a web browser might generate the following request header:

Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

If an HTTP(S) response contains a Qworum message, then servers MUST send this media type in the Content-Type header. Example:

Content-Type: application/xml;charset=utf-8

3.4. The .xml and .qrm file extensions

The RECOMMENDED file extension for Qworum messages is .xml. For example, a file containing a message that calls a payment processing service might be named payment_processing_call.xml.

The .qrm extension uniquely identifies files containing Qworum messages; it MAY be used instead of the more general .xml extension whenever there is a need to ascertain that a file contains a Qworum message by looking at the filename alone, without inspecting the file.

3.5. Message evaluation by the user agent

When a user agent receives a response with the application/xml media type whose root element is a Qworum element, it MUST evaluate the response as a Qworum message. Otherwise, the user agent MUST NOT evaluate the response as a Qworum message.

Most statements yield a result when evaluated. For example, the call statement:

<qrm:call href='email_lookup' xmlns:qrm='http://qworum.net/'>
  <name>John Smith</name>
</qrm:call>

yields a call result, which might be:

<email>john.smith@email.com</email>

And the data statement:

<emails xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name>
  </qrm:call>
  <qrm:call href='email_lookup'>
    <name>Jack Smith</name>
  </qrm:call>
</emails>

might yield:

<emails>
  <email>john.smith@email.com</email>
  <email>jack.smith@email.com</email>
</emails>

The following statements disrupt the flow of evaluation, and consequently do not yield a result:

Message evaluations are interrupted during a service call; they resume when the call terminates. A message evaluation ends when:

The next phase of the current call is initiated when a goto statement is evaluated.

The current call terminates when:

The user agent maintains an internal call stack for handling service calls. In the case of a web browser, each tab or window has a call stack associated with it.

Call stacks initially contain one frame, which represents the main service call. Call frames are used for storing variable values and messages whose evaluations were interrupted by service calls. The topmost call frame, corresponding to the current service call, does not contain any message.

4. Statements

4.1. The call statement

The call statement initiates a multi-phase service call. The evaluation of this statement is interrupted until the call returns a result. The evaluation then ends by yielding the call result.

call elements MAY have an href attribute which indicates the URL of the first phase of the service to be called. The value of the href attribute MUST be an absolute HTTP or HTTPS URL [URL], or a relative URL [RelativeURL]. An absent href attribute is equivalent to an href attribute whose value is the URL of the message containing the call statement, and a relative URL is resolved using the message URL. For example, a request to http://www.ahost.com/path may return any one of the following messages; they will all initiate a call by sending a GET request to http://www.ahost.com/path:

<call xmlns='http://qworum.net/' />

<call href='path' xmlns='http://qworum.net/' />

<call href='http://www.ahost.com/path' xmlns='http://qworum.net/' />

call elements MAY contain a statement called the parameter statement. If the parameter statement is present, then the user agent MUST perform the following sequence of events:

  1. The parameter statement is evaluated.
  2. The evaluation result of the parameter statement is put into a call variable named call parameter, so that all phases of the call to be performed have easy access to it.
  3. The call is initiated with a POST request. The request body contains the evaluation result of the parameter statement. The body content type is either application/xml or application/x-www-form-urlencoded. In the latter case, the control name qworum is used in the body (example: qworum=%3Cemail%3Ejohn.smith@email.com%3C/email%3E). It is RECOMMENDED that user agents use application/xml as the body content type.

call elements contain zero, one or more title elements which briefly describe the call. An OPTIONAL lang attribute indicates the human language that is being used. Accepted values for this attribute are described in the section 3.10 of the HTTP/1.1 [HTTP/1.1] specification. title elements MUST NOT contain any elements.

For example, the following statement:

<qrm:call href='https://www.apaymentprocessingsite.com/process_payment' xmlns:qrm='http://qworum.net/'>
  <qrm:title>Calling the payment processing service ..</qrm:title>
  <payment>
    <description>1 x 1-year subscription for "A Business Magazine"</description>
    <total>98.95</total>
    <currency>USD</currency>
    <merchant>payments@anecommercesite.com</merchant>
  </payment>
</qrm:call>

might send an application/xml POST request to https://www.apaymentprocessingsite.com/process_payment, where the request body (as well as the call variable named call parameter) contains:

<payment>
  <description>1 x 1-year subscription for "A Business Magazine"</description>
  <total>98.95</total>
  <currency>USD</currency>
  <merchant>payments@anecommercesite.com</merchant>
</payment>

The user agent MUST raise an authorization fault instead of evaluating a call statement if the evaluation would redirect the user agent from an internet site to a private or local site.

Internet-to-intranet redirections are prevented by user agents

4.2. The data statement

Data statements are non-Qworum elements that MAY have other non-Qworum elements or statements as descendents. Their evaluation ends when all descendent statements have been evaluated in a depth-first manner. For example, the statement:

<emails>
  <qrm:call href='email_lookup' xmlns:qrm='http://qworum.net/'>
    <!-- this call is evaluated first -->
    <name>John Smith</name>
  </qrm:call>
  <qrm:call href='email_lookup' xmlns:qrm='http://qworum.net/'>
    <!-- this call is evaluated second -->
    <name>Jack Smith</name>
  </qrm:call>
</emails>

may yield:

<emails>
  <email>john.smith@email.com</email>
  <email>jack.smith@email.com</email>
</emails>

And the following statement remains unchanged after evaluation.

<name>John Smith</name>

4.3. The fault statement

The fault statement indicates an error condition that prevents a service call from proceeding normally. Faults can be caught and handled by try statements. Fault example:

<fault xmlns='http://qworum.net/' />

Faults are classified into types which narrow down the underlying cause of an error condition, so that user agents are able to handle each type of fault separately.

Fault types

Faults of type service indicate that the error condition is due to the service which is currently being called. Such faults can be explicitly raised by services. They MAY also be raised by the user agent. In the latter case, some possible causes are:

Faults of type message indicate that the user agent received a Qworum message that does not conform to the present specification.

Services MAY use fault types that are not specified by the present specification. Such types MUST start with the * character and MUST NOT contain the comma (,) character. They are subtypes of the extension type, which is in turn a subtype of service. Example:

<fault type='* parameter is not a name' xmlns='http://qworum.net/' />

Faults of type network indicate that the user agent is unable to execute a call phase, either because it cannot find and connect to the server, or because it was disconnected before it could receive a complete HTTP(S) response. In this situation, the user agent MAY act as if it has received a Qworum message that contains a single network fault.

Faults of type user agent indicate that a user agent issue prevents the current call to proceed normally. The user agent MUST raise a user agent fault if it is unable to evaluate a valid Qworum statement, for example because of an internal error. The user agent MAY also raise a user agent fault if it receives an HTTP(S) response that indicates a client-side issue (such as a 400 Bad Request or 408 Request Timeout response).

The user agent fault type has authorization and user subtypes:

fault elements contain zero, one or more title elements which briefly describe the fault. An OPTIONAL lang attribute indicates the human language that is being used. Accepted values for this attribute are described in the section 3.10 of the HTTP/1.1 [HTTP/1.1] specification. title elements MUST NOT contain any elements. Example:

<fault xmlns='http://qworum.net/'>
  <title lang='de'>Unbekannte Aktie<title>
  <title lang='fr'>Code inconnu<title>
  <title>Unknown ticker symbol<title>
</fault>

The default fault type is service, so that the following statements are equivalent:

<fault type='service' xmlns='http://qworum.net/' />
<fault xmlns='http://qworum.net/' />

4.4. The goto statement

The goto statement initiates the next phase of a multi-phase service call.

goto elements MAY have an href attribute which indicates the URL of the next phase. The value of the href attribute MUST be an absolute HTTP or HTTPS URL [URL], or a relative URL [RelativeURL]. An absent href attribute is equivalent to an href attribute whose value is the URL of the message containing the goto statement, and a relative URL is resolved using the message URL. For example, a request to http://www.ahost.com/path might return any one of the following messages; they will all initiate the next phase of the current call by sending a GET request to http://www.ahost.com/path:

<goto xmlns='http://qworum.net/' />

<goto href='path' xmlns='http://qworum.net/' />

<goto href='http://www.ahost.com/path' xmlns='http://qworum.net/' />

goto elements MAY contain a statement called the parameter statement. If the parameter statement is present, then the user agent MUST perform the following sequence of events:

  1. The parameter statement is evaluated.
  2. The phase is initiated with a POST request. The request body contains the evaluation result of the parameter statement. The body content type is either application/xml or application/x-www-form-urlencoded. In the latter case, the control name qworum is used in the body (example: qworum=%3Cemail%3Ejohn.smith@email.com%3C/email%3E). It is RECOMMENDED that user agents use application/xml as the body content type.

goto elements contain zero, one or more title elements which briefly describe the next phase. An OPTIONAL lang attribute indicates the human language that is being used. Accepted values for this attribute are described in the section 3.10 of the HTTP/1.1 [HTTP/1.1] specification. title elements do not contain any elements.

For example, the following statement:

<qrm:goto href='http://www.anecommercesite.com/process_payment' xmlns:qrm='http://qworum.net/'>
  <qrm:title>Start processing the payment ..</qrm:title>
  <payment>
    <description>1 x 1-year subscription for "A Business Magazine"</description>
    <total>98.95</total>
    <currency>USD</currency>
    <merchant>payments@anecommercesite.com</merchant>
  </payment>
</qrm:goto>

might send an application/xml POST request to http://www.anecommercesite.com/process_payment, and the request body contains:

<payment>
  <description>1 x 1-year subscription for "A Business Magazine"</description>
  <total>98.95</total>
  <currency>USD</currency>
  <merchant>payments@anecommercesite.com</merchant>
</payment>

The user agent MUST raise an authorization fault instead of evaluating a goto statement if the evaluation would redirect the user agent from an internet site to a private or local site.

4.5. The if statement

if is a conditional statement. It MUST contain a condition statement, followed by a "then" statement, followed by an OPTIONAL "else" statement. The default value of the "else" statement is nil.

The condition statement is evaluated first. If it yields nil, then the "else" statement is evaluated, and the if statement yields that value. Otherwise, the "then" statement is evaluated, and the if statement yields that value.

For example, the following statement:

<qrm:if xmlns:qrm='http://qworum.net/'>
  <qrm:nil />
  <text>Positive</text>
  <text>Negative</text>
</qrm:if>

yields:

<text>Negative</text>

4.6. The nil statement

The nil statement represents data that does not carry any information. It remains unchanged after evaluation. Example:

<nil xmlns='http://qworum.net/' />

The nil element MUST NOT have any attributes, and it MUST NOT contain any elements.

4.7. The return statement

The return statement terminates the current call by returning a result. It MUST NOT contain more than one statement. For example, the statement:

<parent>
  <qrm:return xmlns:qrm='http://qworum.net/'>
    <email>john.smith@email.com</email>
  </qrm:return>
</parent>

returns the result:

<email>john.smith@email.com</email>

And the following statement returns nil:

<return xmlns='http://qworum.net/' />

The return element MUST NOT have any attributes.

4.8. The select statement

The select statement is used for selecting an element from the value yielded by the statement it MUST contain. The select element MUST have an xpath attribute whose value is an expression that conforms to the XPath 1.0 specification [XPath/1.0], and it has an OPTIONAL namespaces attribute which defines the namespace prefixes used in the XPath expression.

This statement MUST raise a message fault if the XPath expression is not valid. Otherwise, this statement MUST yield the element that is matched by the XPath expression. If several elements match the XPath expression, then this statement MUST yield the first matched element. It MUST yield nil if the XPath expression:

For example, the following statement:

<qrm:select xpath='/bookshelf/book' xmlns:qrm='http://qworum.net/'>
  <bookshelf>
    <book>
      <title>The XPath Book</title>
    </book>
    <book>
      <title>The XML Book</title>
    </book>
  </bookshelf>
</qrm:select>

yields:

<book>
  <title>The XPath Book</title>
</book>

And the following statement:

<qrm:select xpath='book/d:title' 
  namespaces='d http://purl.org/dc/elements/1.1/ m http://mycompany.com/ns' 
  xmlns:qrm='http://qworum.net/'>
  <bookshelf xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:my='http://mycompany.com/ns'>
    <book>
      <dc:title>The XPath Book</dc:title>
      <my:inventory>22</my:inventory>
    </book>
    <book>
      <dc:title>The XML Book</dc:title>
      <my:inventory>44</my:inventory>
    </book>
  </bookshelf>
</qrm:select>

yields:

<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/">The XPath Book</dc:title>

4.9. The sequence statement

The sequence statement contains zero, one or more statements, each of which is evaluated in turn. The evaluation of this statement yields the result that is yielded by the last statement it contains. For example, the statement:

<qrm:sequence xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name>
  </qrm:call>
  <email>jack.smith@email.com</email>
</qrm:sequence>

yields (if the service call did not terminate with a fault):

<email>jack.smith@email.com</email>

And the following empty statement returns nil:

<sequence xmlns='http://qworum.net/' />

The sequence element MUST NOT have any attributes.

4.10. The transform statement

The transform statement transforms the value yielded by a statement. It MUST contain an XSL stylesheet that conforms to the XSLT syntax [XSLT], followed by the statement whose value is to be transformed. User agents MUST ignore xsl:output elements in the XSL stylesheet.

If the XSL stylesheet is not valid, then the user agent MUST raise a message fault. If the transformation does not yield any value, then the transform statement MUST yield nil.

For example, the following statement:

<qrm:transform xmlns:qrm='http://qworum.net/'>
  <xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
    <xsl:template match="/">
      <books type='nearly out of stock'>
        <xsl:for-each select='*/book[inventory&lt;5]'>
          <book><xsl:value-of select='title' /></book>
        </xsl:for-each>
      </books>
    </xsl:template>
    <xsl:output method='text' /> <!-- ignored by the user agent -->
  </xsl:stylesheet>
  <bookstore>
    <book>
      <title>The XSLT Book</title>
      <inventory>1</inventory>
    </book>
    <book>
      <title>The XML Book</title>
      <inventory>44</inventory>
    </book>
  </bookstore>
</qrm:transform>

will yield:

<books type='nearly out of stock'>
  <book>The XSLT Book</book>
</books>

4.11. The transient statement

The transient statement is used for handling message variables, which exist only during the evaluation of a given message. The transient element MUST have a name attribute which identifies the message variable being handled.

When setting the value of a message variable, the transient element contains one statement which yields the value. The transient statement in turn yields that same value. For example, the statement:

<qrm:transient name='John&apos;s e-mail' xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name>
  </qrm:call>
</qrm:transient>

might yield:

<email>john.smith@email.com</email>

When getting the value of a message variable, the transient element does not contain any element, and the statement yields the value of the message variable. For example, the statement:

<transient name='John&apos;s e-mail' xmlns='http://qworum.net/' />

might yield:

<email>john.smith@email.com</email>

The following statement uses transient in order to avoid code duplication:

<qrm:try xmlns:qrm='http://qworum.net/'>
  <!-- Look for user in first database -->
  <qrm:call href='http://first.user-database/email_lookup'>
    <qrm:transient name='User'>
      <name>John Smith</name>
    </qrm:transient>
  </qrm:call>
  <qrm:catch>
    <!-- User not found in first database -->
    <qrm:try>
      <!-- Look for user in second database -->
      <qrm:call href='http://second.user-database/email_lookup'>
        <qrm:transient name='User' />
      </qrm:call>
      <qrm:catch>
        <!-- User not found in second database -->
      </qrm:catch>
    </qrm:try>
  </qrm:catch>
</qrm:try>

The default value of a message variable is nil.

4.12. The try statement

The try statement allows user agents to handle a fault in order to prevent it from terminating the current call. try statements MUST contain one statement (the tried statement) followed by one or more catch elements.

Each catch element contains zero, one or more statements that are evaluated when a fault is caught by this element. A catch element that does not contain any statement is equivalent to one that contains a nil statement.

catch elements MAY have a types attribute whose value is a comma-separated list of caught fault types. If the types attribute is absent, than the catch element catches all faults.

The evaluation of try starts with the evaluation of the tried statement. If the tried statement is successful, then try yields the result of that statement. For example:

<qrm:try xmlns:qrm='http://qworum.net/'>
  <text>succeeds</text>
  <qrm:catch>
    <text>will never be evaluated</text>
  </qrm:catch>
</qrm:try>

yields:

<text>succeeds</text>

If the tried statement fails because of a fault, then statements in the first catch that matches the fault type are evaluated, and try yields the result of the last statement. For example, the statement:

<qrm:try xmlns:qrm='http://qworum.net/'>
  <qrm:fault />
  <qrm:catch types='message, user agent'>
    <text>fault is of type message or user agent</text>
    <text>0</text>
  </qrm:catch>
  <qrm:catch types='service'>
    <text>fault is of type service</text>
    <text>1</text>
  </qrm:catch>
  <qrm:catch types='service'>
    <text>fault is of type service</text>
    <text>2</text>
  </qrm:catch>
  <qrm:catch>
    <text>fault is of an undetermined type</text>
    <text>3</text>
  </qrm:catch>
</qrm:try>

yields:

<text>1</text>

In the following example, try is unable to handle the failed tried statement. The current call will terminate with a fault, unless an enclosing try statement in the same message handles the fault:

<try xmlns='http://qworum.net/'>
  <fault />
  <catch types='message, user agent' />
</try>

4.13. The variable statement

An issue that quickly arises when developing Qworum services is that of representing call state. Conventional RPC services do not need a mechanism for storing call state, as calls to RPC services always consist of a single phase. In this regard Qworum services are similar to web applications (or websites) whose execution may span several phases, which creates a need for representing a state that is shared between phases.

Qworum addresses the call state representation issue through the concept of call variables. Call variables are stored on the user agent, and they exist throughout the duration of the service call in which they are defined. Call variables are manipulated through the variable statement which has an attribute named name that identifies the variable.

When setting the value of a call variable, the variable element contains one statement which yields the value. The variable statement in turn yields that same value. For example, the statement:

<qrm:variable name='John&apos;s e-mail' xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name>
  </qrm:call>
</qrm:variable>

might yield:

<email>john.smith@email.com</email>

When getting the value of a call variable, the variable element does not contain any element, and the statement yields the value of the call variable. For example, the statement:

<variable name='John&apos;s e-mail' xmlns='http://qworum.net/' />

might yield:

<email>john.smith@email.com</email>

The following statement sets the value of a call variable and initiates the next phase:

<qrm:sequence xmlns:qrm='http://qworum.net/'>
  <qrm:variable name='Username'>
    <username>john.smith</username>
  </qrm:variable>
  <qrm:goto href='call_variable_is_set' />
</qrm:sequence>

The default value of a call variable is nil.

Note:
Qworum variables are the RECOMMENDED method for storing call state. Proceed with caution when using other methods. In particular, existing client-side storage mechanisms such as HTTP cookies and HTML5 localStorage/sessionStorage objects SHOULD NOT be used for storing call state, because:

  • This would lead to the call state being shared between browser tabs, which would prevent services from running simultaneously in more than one tab.
  • This would overwrite the state of previous calls when performing recursive calls.

5. Implementations

User agents that conform to the present specification MUST provide at least one of the following capabilities:

In addition, user agents which implement the present version of the Qworum core specification MUST also implement the following specifications:

5.1. The qworum JavaScript object

User agents that can handle HTML documents MUST provide a JavaScript object named qworum.

5.1.1. The qworum.features object

The qworum object MUST have a features property, which is an object that describes the user agent's Qworum capabilities. It contains following properties:

5.1.2. The qworum.eval() function

It is RECOMMENDED that user agents provide a JavaScript function named qworum.eval(). When this function is called, user agents MUST behave as if they have received a Qworum message. Examples:

// call a service
var message = ['goto', 'receive_result', 
  ['call', 'http://example.com/service', 
    ['json', 89]
  ]
];
qworum.eval(message);
/* evaluates:
<goto href='receive_result' xmlns='http://qworum.net/'>
  <call href='http://example.com/service'>
    <data xmlns='http://qworum.net/json'>
      89
    </data>
  </call>
</goto>
*/

// raise a fault
message = "<fault xmlns='http://qworum.net/' />";
qworum.eval(message);

// return a result 
message = ['json', 'Hello, World !'];
qworum.eval(message);

The message argument of this function MUST conform to the following rules:

Further examples:

// call 
['call', 'http://example.com/service']

['call', 'http://example.com/service',
  ['json', {firstName: 'John', lastName: 'Smith'}]
]

['call', 'http://example.com/service',
  '<param>value</param>',
  'Some title.'
]

// data 
'<email>john.smith@email.com</email>'

// fault 
['fault']

['fault', '* reason']

['fault', null,
  'Some title.'
]

// goto 
['goto', '/some/phase']

['goto', 'phase',
  ['json', 'value']
]

['goto', 'some/phase',
  null,
  'Some title.'
]

// nil 
['nil']

// if 
['if', ['nil'],
  ['json', 'ignored'],
  ['json', 'chosen']
]

['if', ['nil'],
  ['json', 'ignored']
]

// return 
['return']

['return',
  ['call', 'http://example.com/service']
]

// select 
['select', '/bookshelf/book', null,
  "<bookshelf>\n"+
  "  <book>\n"+
  "    <title>The XPath Book</title>\n"+
  "  </book>\n"+
  "  <book>\n"+
  "    <title>The XML Book</title>\n"+
  "  </book>\n"+
  "</bookshelf>"
]

['select', 'book/d:title, 'd http://purl.org/dc/elements/1.1/ m http://mycompany.com/ns',
  "<bookshelf xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:my='http://mycompany.com/ns'>\n"+
  "  <book>\n"+
  "    <dc:title>The XPath Book</dc:title>\n"+
  "    <my:inventory>22</my:inventory>\n"+
  "  </book>\n"+
  "  <book>\n"+
  "    <dc:title>The XML Book</dc:title>\n"+
  "    <my:inventory>44</my:inventory>\n"+
  "  </book>\n"+
  "</bookshelf>\n"
]

// sequence 
['sequence',
  ['json', 'ignored'],
  ['json', 'chosen']
]

// transform 
['transform',
  "<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>\n"+
  "  <xsl:template match=\"/\">\n"+
  "    <books type='nearly out of stock'>\n"+
  "      <xsl:for-each select='*/book[inventory<5]'>\n"+
  "        <book><xsl:value-of select='title' /></book>\n"+
  "      </xsl:for-each>\n"+
  "    </books>\n"+
  "  </xsl:template>\n"+
  "  <xsl:output method='text' /> \n"+
  "</xsl:stylesheet>\n",

  "<bookstore>\n"+
  "  <book>\n"+
  "    <title>The XSLT Book</title>\n"+
  "    <inventory>1</inventory>\n"+
  "  </book>\n"+
  "  <book>\n"+
  "    <title>The XML Book</title>\n"+
  "    <inventory>44</inventory>\n"+
  "  </book>\n"+
  "</bookstore>\n"
]

// transient 
['transient', 'some name']

['transient', 'some name',
  ['json', 'value']
]

// variable 
['variable', 'some name']

['variable', 'some name',
  ['json', 'value']
]
// try 
['try',
  ['call', 'some/service'],
  ['network',
    ['json', 'handle network fault']
  ],
  ['service',
    ['json', 'handle service fault']
  ],
  [null,
    ['json', 'handle all faults']
  ]
]

5.1.3. The qworum.set() and qworum.get() functions

It is RECOMMENDED that user agents allow the manipulation of call variables (stored in the current call frame) through JavaScript functions called qworum.set() and qworum.get(). These are similar to localStorage.setItem() and localStorage.getItem() [WebStorage], except that values are stored as XML or XML-wrapped JSON:

Example:

// set the value of local variable 'v' for current call
qworum.set('v', 89);
/* stored as:
<data xmlns='http://qworum.net/json'>
  89
</data>
*/

// get the value of 'v' variable
var v = qworum.get('v'); // 89

5.1.4. The qworum.config object

It is RECOMMENDED that user agents provide a JavaScript object named qworum.config, which is used for modifying the behaviour of the qworum.eval() function.

This object MAY contain the following properties:

The initial value of qworum.config is {} when a web page is (re)loaded. This means that default values are used for all its allowed properties, unless they are overridden as follows:

// set one or more properties
qworum.config = {
  replaceState: true
};

// or set one property at a time
qworum.config.navigate = function(pathname, search, hash) {
  // pathname: a string that contains the full path; always starts with '/'
  // search:   contains the query string which starts with '?', or is empty ('')
  // hash:     contains the fragment string which starts with '#', or is empty ('')
  hash = hash.substring(1);

  // use Backbone.js navigation capabilities
  application.navigate(hash, {trigger: true, replace: true});
};

// the call below will not generate a POST request
qworum.eval(['goto', '#receive',
  ['variable', 'result',
    ['call', '#service',
      ['json', {name: 'Dave'}]
    ]
  ]
]);

5.1.5. The qworum.my object

Single-page services/applications often use client-side JavaScript frameworks such as Backbone.js, which define their own object types (e.g. models) for representing state. Qworum aims to offer 100% compatibility with all frameworks, consequently it is RECOMMENDED that user agents provide a qworum.my object for storing non-Qworum objects:

5.2. HTML-based linking

Web browsers MAY provide support for data-qworum and data-qworumc HTML attributes. When a click event is triggered on the associated HTML element, a defined Qworum message is evaluated. The user experience is similar to clicking on a hyperlink.

5.2.1. The data-qworumc HTML attribute

The data-qworumc attribute refers to an element (in the same page) that contains a Qworum message.

Elements containing Qworum messages MAY have a type attribute which defines the message MIME type. Its default value is application/x-qworum-json, which corresponds to the JSON-encoding of the array-based message format used by the argument of qworum.eval().

Example:

<p>
  Finished shopping?
  <a data-qworumc='#checkout'>Proceed to checkout</a>
</p>
<script id='checkout' type='application/x-qworum-json'>
  ["goto", "receive",
    ["variable", "result",
      ["call", "http://www.example.com/checkout", 
        ["json", {"cartId": 1349962508}]
      ]
    ]
  ]
</script>

5.2.2. The data-qworum HTML attribute

The data-qworum attribute contains a Qworum message which conforms to the format used by qworum.eval(), JSON-encoded.

The following example:

<p>
  <a data-qworum='[&quot;goto&quot;, &quot;goto/page/9&quot;]'>Next page</a>
</p>

is equivalent to:

<p>
  <a data-qworumc='#next'>Next page</a>
</p>
<script id='next' type='application/x-qworum-json'>
  ["goto", "/page/9"]
</script>

The data-qworum has priority over data-qworumc.

5.3. Synchronisation

In order to prevent call stacks from going out of sync with the web pages that end-users manipulate, it is RECOMMENDED that web browsers clear the URL history of tabs up to, and including, the URL of the latest received Qworum message.

5.4. Target frame

It is RECOMMENDED that user agents do not allow end-users to choose the target frame of a link during service calls.

5.5. Referrer

In addition, it is RECOMMENDED that user agents send correct Referer headers when evaluting call or goto statements. For example, if the user agent receives the message below from http://www.example.com/msg, then the Referer header of the HTTP request it generates when evaluting the goto statement MAY contain http://www.example.com/msg (e.g. rather than the URL of the last phase of the service call http://www.example.com/email_lookup, which would be incorrect):

<qrm:goto href='receive_email_address' xmlns:qrm='http://qworum.net/'>
  <qrm:call href='email_lookup'>
    <name>John Smith</name>
  </qrm:call>
</qrm:goto>

5.5. Bookmarking

It is further RECOMMENDED that user agents do not allow end-users to bookmark pages during service calls.

6. Appendices

6.1. References

[HTTP/1.1] Berners-Lee, T., Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., and Leach, P., Hypertext Transfer Protocol -- HTTP/1.1, RFC 2616
[HTTP/1.0] Berners-Lee, T., Fielding, R. and Frystyk, H., Hypertext Transfer Protocol -- HTTP/1.0, RFC 1945
[HTTPS] Rescorla, E., HTTP Over TLS, RFC 2818
[URL] Berners-Lee, T., Masinter, L., and McCahill, M., Uniform Resource Locators (URL), RFC 1738
[RelativeURL] Fielding, R., Relative Uniform Resource Locators, RFC 1808
[XML] Tim Bray, Jean Paoli, C. M. Sperberg-McQueen, Eve Maler, Fran├žois Yergeau, Extensible Markup Language (XML), W3C Recommendation
[XMLnamespaces] Tim Bray, Dave Hollander, Andrew Layman, Richard Tobin, Namespaces in XML 1.0, W3C Recommendation
[XPath/1.0] James Clark, Steve DeRose, XML Path Language (XPath), Version 1.0, W3C Recommendation
[XSLT] James Clark, XSL Transformations (XSLT), Version 1.0, W3C Recommendation
[TLD] Top-level domain
[IPaddress] IP address
[Loopback] Loopback IP address
[Keywords] Bradner, B., Key words for use in RFCs to Indicate Requirement Levels, RFC 2119
[DRM/1.0] Doğa Armangil, Qworum Digital Rights Management (DRM) specification, version 1.0
[Enterpise/1.0] Doğa Armangil, Qworum Enterprise specification, version 1.0
[JSON] Doğa Armangil, JSON data types for Qworum, version 1.0
[WebStorage] Web Storage

6.2. Revision history

2012.10.23 Define the data-qworumc HTML attribute.
2012.10.19 Define qworum.features JavaScript object.
2012.10.11 Define the data-qworum HTML attribute.
2012.10.09 Merge qworum.state with qworum.
2012.10.05 Define the qworum.config.navigate property.
2012.09.28 Define qworum.config and qworum.my JavaScript objects.
2012.06.14 Define qworum.eval JavaScript function.
2012.05.30 Define qworum.state JavaScript object.
2012.01.10 Fix typo in section 4.10.
2011.11.02 Add recommendations in section 5.
2011.10.18 Update abstract.
2011.09.11 Add user fault type.
2010.11.22 Change the media type of Qworum messages to application/xml; application/x-www-form-urlencoded is now allowed (though not recommended) as the request body content type.
2010.06.10 Add the transform statement.
2010.06.04 Add the if and select statements.
2010.04.05 Initial release of 1.0 draft.
2007.09.06 First draft.

6.3. Copyright and disclaimer

© Copyright 2007-2012 Doğa Armangil. All Rights Reserved.

This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and these paragraphs are included on all such copies and derivative works. This document may not be modified in any way, such as by removing the copyright notice or references to Doğa Armangil or other organizations.

Any party may, for commercial or non-commercial purposes, send Qworum messages from web servers to user agents, without royalty or license fee to Doğa Armangil.

In addition, any party may, without royalty or license fee to Doğa Armangil, implement client-side software which conform to the present specification, allowing web browsers and other user agents to handle Qworum messages.

THIS DOCUMENT AND THE INFORMATION CONTAINED HEREIN IS PROVIDED "AS IS", AND DOĞA ARMANGIL DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. FURTHER, DOĞA ARMANGIL WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THIS DOCUMENT.