Intent

To define a view of a single workflow task in a long-running process. The application data is represented as RDF data and the resource is an instance of a class that is required to be presented to the user. A typical state-change is represented as the monotonically increasing assertion of time-stamps. This helps to avoid the possibility of inconsistent states and removes the need for an RDF deletion.

Motivation

Applications often need to transition through a series of states, performing one significant task after another, and indicating to the user which tasks have been completed and what task is next. For example, an application may transition through state A, B, C and D. In a non-monotonic programming environment such as Java, one might use a state variable to indicate the current state, and (non-monotonically) modify this variable as the state changes:

currentState = S1;   // Initial state
  [ Perform some task T1 ]
currentState = S2;
  [ Perform another task T2 ]
currentState = S3;
  [ Perform yet another task T3 ]
currentState = S4;

However, if the state is being stored in RDF, changing the state this way is not so convenient, because it means that a /:currentState/ property must be continually deleted and re-asserted:

INSERT DATA { :app :currentState :S1 }   # Initial state
## Perform some task T1 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S2 }
## Perform another task T2 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S3 }
## Perform another task T3 ##
DELETE WHERE { :app :currentState ?s }
INSERT DATA { :app :currentState :S4 }

Such timestamps can also be useful for display to the user or for logging progress.

This style of programming also meshes nicely with the way state transitions are handled in the REST programming style. Several years ago Paul Prescod posted a nice explanation of this to a mailing list. (If anyone can provide a link, please do so.) In lieu of that, he has a pretty good description here: http://www.prescod.net/rest/state_transition.html .

Applicability

Consider using this pattern where the state of a resource must change over time and the resource is to be represented as RDF metadata.

Implementation

The view is constructed as a Callimachus XHTML template with RDFa properties. The subject of these properties, in both the head and body, is the task resource denoted by '?this'. Stateful properties are not displayed directly but are consumed by javascript and used to update the displayed status. The date-time of completion is shown using the standard datetime-locale layout. The status may change while the view page is open, so the javascript in the head reloads the page after a suitable interval.

Sample Code

The application metadata defines the relationship between the class of resource and the RDFa template:

@prefix eg: <http://example.com#>.
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix calli: <http://callimachusproject.org/rdf/2009/framework#>.

eg:MyStatefulClass rdfs:subClassOf calli:Viewable ; calli:view <my-stateful-class.xhtml> .

The RDFa XHTML template my-stateful-class.xhtml contains:

 <?xml version="1.0" encoding="UTF-8" ?>
 <html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
   xmlns:eg="http://example.com#">
   <head>
      <title resource="?this">{rdfs:label}</title>
      <script>setTimeout(function() {document.location.reload(false)}, 300000)</script>
   </head>
   <body resource="?this">
     <h1 property="rdfs:label" />
     <div id="status">
       <span property="eg:startedT1At" content="?t1">
          Step 1 since <time class="abbreviated">{?t1}</time>
       </span>
       <span property="eg:startedT2At" content="?t2">
          Step 2 since <time class="abbreviated">{?t2}</time>
       </span>
       <span property="eg:startedT3At" content="?t3">
          Step 3 since <time class="abbreviated">{?t3}</time>
       </span>
       <span property="eg:finishedAt" content="?t4">
          Finished since <time class="abbreviated">{?t4}</time>
       </span>
     </div>

     <script type="text/javascript"><![CDATA[
        // only show the last status
        $("#status>span:not(:last)").remove();
     ]]></script>

   </body>
 </html>