PropertyRendering Util Documentation

Purpose and Basic Operation

The property rendering utility renders a HTML from for a resource using a template and an OWL ontology. The form can be filled in to create a new instance of the resource as specified by the OWL ontology. This enables application programmers to create templates for forms that allow users to easily create or update instances of a resource while enforcing the defined ontology. This doesn't require any programming knowledge on the side of the user. The utility offers full flexibility to the application programmer to implement his own visualization and save/update logic. As a result semantic web technology can be exploited by having resource types defined as OWL ontologies which allows for flexibility and consistency.

 
The PropertyRendering utility process flow is depicted in the diagram above. Throughout this document the example of rendering a basic article type document is used.

Prerequisites:

  • There exist an article template (see section "The Template" for details) for the Article type.
  • There exists an article OWL ontology (see section "The Ontology" for details).
  • The article application has registered a renderlet with a custom rendering mode (e.g. "edit-article" for resources of type Article). The renderlet render the article's template instead of the article itself.
  • The article application has registered custom ObjectTypeHandlers custom types (e.g. a rating handler) it requires.

The processes are:

  1. An application offers the user an option to edit or create an article. When the user chooses that option, the article is rendered with ?mode="edit-article" (in this example).
  2. Instead of the article's RDF content to be dispalyed, the previously registered renderlet redirects to the article's template instead.
  3. The template is rendered and all nodes of type propertyrendering:PropertyTemplate are rendered by the PropertyRenderlet. A RestrictionParser is used to extract semantic information (e.g. an article has exactly one title) from the article's ontology. Registered ObjecttypeHandlers are used to determine how to visually represent properties in the resulting input form.
  4. The PropertyRenderlet generates an HTML Form by rendering all property templates. If the article instance is empty, all fields are blank. If the article instance already had data, then the fields are populated with that data. This enables a user to create a new article instance that conforms to the ontology or to update an existing article instance.
  5. The user submits the filled in form.
  6. The TemplateFormParser parses the submitted data and lets the responsible ObjecttypeHandlers interpret it to generate RDF data. To check for consistency with the Ontology it the RestrictionParser is used again. The result is a new or updated article instance in RDF.

The Template

The template file uses the discobits ontology. It uses ordered content to specify the order of the rendered properties in the resulting HTML form. It also specifies which properties are rendered and how. For this purpose resources with the rdf:type propertyrendering:PropertyTemplate are defined and a rendering mode is assigned to them. A property template needs to specify the following properties:

  • propertyrendering:property - the property that this template renders
  • propertyrendering:restrictionClass - the OWL class that this property belongs to (the OWL class that defines restrictions for this property)
  • propertyrendering:mode - a string that is used to differentiate rendering modes (such as render as textfield, render as radio button, etc.)

Creation of a template is currently complex to do by hand. There exist no tools to create a template either but the idea is that it will be created using a tools in future.
TODO: how to use different ontology classes by recursively defining templates/show structure of a template/predefined modes

The Ontology

The ontology parser currently only supports a custom subset of OWL. Therefore not all OWL expressions are supported. Currently it is recommended to use the Protegé OWL Editorto create an ontology. When sticking to some basic design patterns the ontology should be compatible.

  • define restrictions as superclass restrictions (equivalent classes are not supported)
  • do not mix different classes or data types in single restriction stanzas
  • and and or restrictions are not supported - however all restrictions stanzas together are interpreted as conjuncted (and-connected).
  • inference along explicit class hierarchy is supported
  • restrictions can be defined in the class definition and in the property definition.
  • it is best to define restrictions for cardinality and restrictions for the content (xsd facets) in separate stanzas.
  • the rdfs:label is used to define how to display the name of form fields (e.g. "Tite" followed by a text input box)

TODO: list more predefined property interpretations

Using the Property Rendering Utility in an Application

The PropertyRendering Core bundle provides the following services:

  • A PropertyRenderlet (you don't need to worry about this. It registers itself to process all resources of type PropertyTemplate with rendering mode "naked").
  • A RestrictionParser to extract semantic information from the ontology (normally you do not need to use this service directly)
  • A RestrictionElementRegistry (you only need to use this service if you want to extend the capabilities of the restriction parser - for example to extend the OWL compatibility)
  • A TemplateFormParser - this is an important service that lets you process the form fields filled out by a user.
  • An ObjecttypeManager - this service gives access to all registered ObjecttypeHandlers, including your own. 

When your application wants to use the property rendering utility it is responsible to to provide a template. The ontology is assumed to be defined in the graph configured as the ontology graph at the RestrictionParser. If this is not the case your application needs to write the ontology into that graph before it is used for the first time. Furthermore your application needs to register a Renderlet with a custom rendering mode for rendering the HTML form.

The code to register a renderlet looks like this (note the custom mode "edit-article" and the type "http://clerezza.org/ontologies/2010/11/article#Article", this needs to be adapted to your application):

ResourceFinder resourceFinder = new ResourceFinder(context, getClass());
URL ssp = resourceFinder.find("edit-article.ssp");
renderletManager.registerRenderlet(ScalaServerPagesRenderlet.class.getName(),
	new UriRef(ssp.toURI().toString()),
	new UriRef("http://clerezza.org/ontologies/2010/11/article#Article"), "edit-article",
	MediaType.APPLICATION_XHTML_XML_TYPE, true);

A minimalist Renderlet can look like this (edit-article.ssp):

def rdf(s: Any) = new UriRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#" + s)
def propertyrendering(s: Any) = new UriRef("http://clerezza.org/ontologies/2010/11/propertyrendering#" + s)

<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en">
	<head>
		<link type="text/css" href="/style/style.css" rel="stylesheet" />
		<title>Edit Article</title>
	</head>
	<body>
		<form method="POST" action="" enctype="multipart/form-data">
			{render(res/rdf("type")/propertyrendering("hasTemplate"), "naked")}
			<input type="submit">Submit</input>
		</form>
	</body>
</html>

The most important line is render(res/rdf("type")/propertyrendering("hasTemplate"), "naked"). This causes the template to be rendered using the PropertyRenderlet.

Then all your application needs to do is to provide JAX-RS resources to retrieve resources of your type (article) and to handle the POST request when the form is submitted. In order to deal with the submitted form you have to use the TemplateFormParser service as follows:

@Reference
private TemplateFormParser templateFormParser;

@POST
@Consumes("multipart/form")
public TripleCollection saveArticle(MultiPartBody multiPartBody) {
	UriRef articleUri = new UriRef("http://example.org/article1");
	GraphNode article = templateFormParser.parse(multiPartBody, getTemplate(), articleUri);
	return article.getGraph();
}

The TemplateFormParser requires you to submit the body of the request, the template file, and the name of URI of the instance that it will create or edit. The TemplateFormParser returns a GraphNode representing the new or updated instance. Your application is responsible to save this persistently.

The property rendering core bundle provides some default ObjecttypeHandlers but your application is very likely to require custom ones as well. You can easily implement your own ObjecttypeHandler for this purpose. An example of a basic ObjecttypeHandler is:

 @Component
 public class MyHandler extends ObjectTypeHandler {

	private static final String MY_MODE = "my-super-special-mode";

	//Returns true if this handler can handle this property.
	@Override
	public boolean isApplicable(String mode, PropertyRestrictionInfo restriction) {
		if(mode.equals(MY_MODE)) {
			return true;
		}
		return false;
	}

	@Override
	protected GraphNode enrichPropertyTemplate(GraphNode propertyTemplate, GraphNode context, String mode,
			PropertyRestrictionInfo propertyInfo) {

		propertyTemplate.addProperty(FOAF.name, new PlainLiteralImpl("Bob"));
		propertyTemplate.addProperty(FOAF.name, new PlainLiteralImpl("Alice"));

		return propertyTemplate;
	}

	@Override
	public Resource addResourceToGraph(GraphNode fillNode, String mode, MultiPartBody multiPartBody, PropertyRestrictionInfo propertyInfo) {
		String data = multiPartBody.getTextParameterValues(propertyInfo.getProperty().getUnicodeString())[0];
		Literal l = null;
		if(data.equals("Bob")) {
			l = new PlainLiteralImpl("Bob");
		} else {
			l = new PlainLiteralImpl("Alice");
		}


		fillNode.addProperty(propertyInfo.getProperty(), l);

		return l;
	}

	/**
	 * Called when this component is started.
	 *
	 * @param context The Component context.
	 */
	protected void activate(ComponentContext context) throws URISyntaxException {
		ResourceFinder resourceFinder = new ResourceFinder(context, getClass());

		URL userSelectWidget = resourceFinder.find("myWidget.ssp");
		renderletManager.registerRenderlet(ScalaServerPagesRenderlet.class.getName(),
				new UriRef(userSelectWidget.toURI().toString()),
				PROPERTYRENDERING.PropertyTemplate, EDIT_USER_PICKER,
				MediaType.APPLICATION_XHTML_XML_TYPE, true);
	}

 }

The isApplicable method must be implemented so that it returns true when this handler can deal with the currently rendered property.

The enrichPropertyTemplate method is called before the current property is rendered. It allows to add data to the rendered resource that is then available in the corresponding SSP. The SSP is registered in the activate method for the type propertyrendering:PropertyTemplate.

The addResourceToGraph method is called when the generated form is being saved. It allows the handler to construct a resource that is added to the Graph (fillGraph). This allows to customize what is saved and how.

The following is an example of the registered SSP (myWidget.ssp). The SSP defines how a property is displayed in the generated form and what functionality it has:

 import org.apache.clerezza.rdf.core.UriRef
 import org.apache.clerezza.rdf.core.NonLiteral
 import org.apache.clerezza.rdf.core.Literal
 import org.apache.clerezza.rdf.utils.RdfList

 import scala.collection.JavaConversions._

 def rdf(s: Any) = new UriRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#" + s)
 def rdfs(s: Any) = new UriRef("http://www.w3.org/2000/01/rdf-schema#" + s)
 def propertyrendering(s: Any) = new UriRef("http://clerezza.org/ontologies/2010/11/propertyrendering#" + s)

 <div>
	{(res/rdfs("label"))*}
	<select class={mode} name={ res/propertyrendering("property")* }>
	{
		<option selected="selected">Bob</option>
		<option>Alice</option>
	}
	</select>
 </div>

TODO: predefined properties available in ssp.

Labels