Skip to content

Application development manual

Jean-Marc Vanel edited this page Jan 24, 2021 · 26 revisions

Table of Contents

Customize generic application

The operations to create a business application with the semantic_forms web framework are described below in the logical order.

We remind that the generic application is perfectly usable out of the box, see User_manual. However, it is better to preload common RDF vocabularies and related form specifications and I18N translations, see: preloading-rdf-content .

The more basic README information (run locally from sources or from distribution, setting a IDE project, RDF and Lucene database administration) is here: https://github.com/jmvanel/semantic_forms/tree/master/scala/forms_play#play-framework-implementations

The ingredients of the forms receipe

The forms receipe is cooked fresh at each HTTP request!

Case of existing instance:

instance URI            |
form specification      |----> form
ontology                |
overriden labels        |

Case of creating new instance:

class URI, or           |
form specification      |----> form
ontology                |
overriden labels        |

Create specific ontology

The ontologies are to be stored in the database. They specify basically:

  • properties having rdfs:domain and rdfs:range.
  • classes which are the domain and/or range of properties

For instance, the property foaf:currentProject goes from class foaf:Person to class foaf:Project .

Just like any data, the ontologies are managed by the semantic cache.

They can be loaded either by the top page field in the generic application ( see navigating and loading semantic data ), or offline by the tdb.tdbloader Jena utility (see database administration).

An ontology (RDF vocabulary) can be created with any tool:

  • with Protégé ontology editor
  • in Turtle with a text editor and syntax coloring (Vim, gedit, ...)

We don't have yet the ability within semantic_forms to create or edit an RDF vocabulary; this related to issue #24 https://github.com/jmvanel/semantic_forms/issues/24

Create specific form specification

By default, an automatic form generated in semantic_forms contains all the available RDF properties for given OWL class, for a creation form. For an pre-filled form (modification form), the form contains all the available RDF triples in the triple database.

A form specification allows to:

  • specify which RDF properties, and in in which order, will be displayed for which OWL class
  • specify details of how a property will be displayed for edition ( mainly, use DBPedia lookup )

Here is an example of a form specification that is loaded by program

deductions.runtime.sparql_cache.PopulateRDFCache

It says "for foaf:Person, for an empty form (creation form), use only there properties in this order" :

<personForm>
  form:classDomain foaf:Person ;
  form:showProperties (
	foaf:givenName foaf:familyName
	foaf:homepage
	foaf:mbox
	foaf:phone
	foaf:img
	foaf:topic_interest
	foaf:knows
	foaf:currentProject
	cco:expertise
  ) .

See foaf.form.ttl for the complete file.

As you can see, a form specification basically is an ordered list of RDF properties. A form specification has an URI that is used in the /form web service. It is stored in the SPARQL database.

We don't have yet the ability within semantic_forms to create or edit a form specification; this is related to issues : https://github.com/jmvanel/semantic_forms/issues/28 https://github.com/jmvanel/semantic_forms/issues/22

However, there is a useful utility that writes a skeleton of a form specification from a given OWL class: FormSpecificationsFromVocabApp

Services specified by W3C recommandations: LOD, SPARQL, LDP

LOD (Linked Open Data)

This is the vintage, and ever valid, RDF service. Live hosted URI's, eg. http://semantic-forms.cc:9112/ldp/semantic_forms, return RDF, one of the 3 syntaxes according to the HTTP header "Accept". This is called content negotiation. There is also the service /download which does the same thing but via a parameter "syntax" in the URL; see in a /display web page the links: Data export: Triplets Turtle - Triples JSON-LD - Triplets RDF / XML .

SPARQL

Here are the services specified by the SPARQL protocol W3C recommandations:

  • /sparql : SPARQL query
  • /update : SPARQL update
  • /load : SPARQL 1.1 Graph Store ( see below )

To run /update , you must be logged in as a user, just like when you do /edit .

This user can be any one. There is a script that does everything: connection + /update : rupdate.sh in https://github.com/jmvanel/semantic_forms/tree/master/scala/forms_play/dist/script . There is also a Python script rupdate.py .

LDP (Linked Data Platform)

There is a partial implementation of LDP (Linked Data Platform); the service is at '/ldp' . It reacts to GET, POST, PUT and OPTIONS HTTP requests. The prefix '/ldp/' is also used for URI's created by /create forms.

Notable differences from the W3C recommandation:

  • when PUTting or POSTing to relative URI /a/b/my.ttl , the container /a/b/ does not have to be created in advance
  • storing non-RDF data (e.g. images) is not implemented

LDP is a copious specification, and only the fundamental features are implemeted at the moment. The official test suite is used to track implemeted features.

The correspondance between the SPARQL database and the LDP services is thus: when PUTting or POSTing to relative URI /a/b/my.ttl, the corresponding absolute URI will become a graph in SPARQL database, whose content will be the content sent by LDP protocol.

Add specific pages

UI for Application developer

The /tools page has a link at bottom left.

This page is an RDF views and queries testing tool, since you can launch different tools on the same graph via a SPARQL query.

For a SPARQL construct query, these views are available:

  • plain Turtle
  • geographical map,
  • table

For a SPARQL SELECT query, these views are available:

  • plain table
  • history

Once your view is tested, you can add a link to it in a Web page created in SF itself through the HTML editor.

This page is also a real RDF visual tools comparison laboratory, since you can launch different tools on the SPARQL seerver:

  • YasGUI
  • Sparklis,
  • SPARQL surveyor

Client side with SF Web services API

It is possible to create applications from the zip release, by calling web services from JavaScript, so without recompiling the Play! application. Several services are used for this:

  • /form,
  • /form-data
  • /create-data,
  • /sparql-data, and
  • /files.

The /save service is called by default from the forms generated by /edit, /form, /display?Edit=edit . The HTML names of the input fields are the URL-encoded string from the original triples (in Turtle) from the database. So the server is able to associate the user input with the original triple.

The /form web service

The /form web service is the easiest way to generate forms within the layout of your application pages. That is, you get the semantic_forms form in HTML without the top and bottom of page present in the generic semantic_forms application.

Here is an example of a web page using JavaScript to call the 3 different variants of the /form web service: http://ldp.virtual-assembly.org:9111/assets/example1.html There a 3 variants:

  • Display existing data about a subject URI
  • Create a new instance of a given OWL class
  • Modify (edit) existing data

The HTML + JS source code is here: https://github.com/jmvanel/semantic_forms/blob/master/scala/forms_play/public/example1.html

Here is a fragment of JavaScript in this page:

// Edition: give URI instance (FOAF profile), and form specification URI
		loadForm(
			'/form?displayuri=' + encodeURIComponent( 'http://jmvanel.free.fr/jmv.rdf#me' ) +
			'&formuri=' + encodeURIComponent( 'http://deductions-software.com/ontologies/forms#personForm' ) +
			'&Edit=yes',
			'edit' );

The /form-data web service

The /form-data web service is the most flexible way to generate forms within the layout of your application pages. This service outputs the raw data in JSON , the same data from which the form in HTML is generated in the generic semantic_forms application.

Here is an example of calling the service: get the raw data for a view of a FOAF profile:

http://localhost:9000/form-data?displayuri=http://jmvanel.free.fr/jmv.rdf%23me

There you get the default form specification for the foaf:Person class. If you want another form specification do this:

http://localhost:9000/form-data?displayuri=http://jmvanel.free.fr/jmv.rdf%23me&formuri=http://www.virtual-assembly.org/ontologies/1.0/forms%23PersonForm

The (facultative) ) added HTTP parameter formuri is the URI of the form specification. If the form specification is not self-hosted, it must be loaded somewhere into the database, like any data or ontology; see link for loading RDF content into the database

Adding this to previous URL specifies to add or use RDF content in database located in PRIV/ directory (otherwise in default directory TDB).

&database=PRIV

Adding this to previous URL results in a edition form:

&Edit=yes

The /create-data web service

Like the /form-data web service, the /create-data service returns a "rich" JSON data structure described here. It takes the same HTTP parameters as the /create web page:

uri=
formuri=

For example:

http://localhost:9000/create-data?uri=&uri=http%3A%2F%2Fraw.githubusercontent.com%2Fjmvanel%2Fsemantic_forms%2Fmaster%2Fvocabulary%2Fforms%23personForm

The /create-html web service

Like the /create service, it produces a input form for creating ar instance of given class. But it has no web page header.

NOT YET IMPLEMENTED.

JSON format returned by the services

This format represents a list of triples, that is an RDF graph, but it's not JSON-LD; the form fileds are an array of flat JSON structures. It contains exactly the strings a,d images displayed by the forms in SF application. It has :

  • all the information JSON-LD has ("subject", "property", "value")
  • URI's in extenso (no prefixes), simpler for JSON developers, and not needing a JavaScript RDF library.
  • computed data ready for I18N displaying: labels ("subjectLabel", "valueLabel", "label" for property), images ("thumbnail", if available)

Hopefully it can be reused also by non-RDF applications, to share web components.

Here is a JSON fragment gotten from the /form-data service:

{
  "subject" : "http://jmvanel.free.fr/jmv.rdf#me",
  "title" : "Jean-Marc Vanel",
  "thumbnail" : "http://jmvanel.free.fr/images/jmv_id.jpg",
  "formURI" : "http://www.virtual-assembly.org/ontologies/1.0/forms#PersonForm",
  "formLabel" : "forms#PersonForm",

  "fields" : [

{
    "subject" : "http://jmvanel.free.fr/jmv.rdf#me",
    "subjectLabel" : "Jean-Marc Vanel",
    "property" : "http://xmlns.com/foaf/0.1/firstName",
    "label" : "firstName",
    "comment" : "The first name of a person.",
    "mandatory" : false,
    "value" : "Jean-Marc",
    "type" : "http://www.w3.org/2000/01/rdf-schema#Literal",
    "widgetType" : "Text WidgetType",
    "openChoice" : true,
    "cardinality" : "0:*",
    "htmlName" : "%3Chttp%3A%2F%2Fjmvanel.free.fr%2Fjmv.rdf%23me%3E+%3Chttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2FfirstName%3E+%22Jean-Marc%22+.%0A"
  },

{
    "subject" : "http://jmvanel.free.fr/jmv.rdf#me",
    "subjectLabel" : "Jean-Marc Vanel",
    "property" : "http://xmlns.com/foaf/0.1/schoolHomepage",
    "label" : "schoolHomepage",
    "comment" : "A homepage of a school attended by the person.",
    "mandatory" : false,
    "value" : "http://www.ens-cachan.fr/",
    "type" : "http://xmlns.com/foaf/0.1/Document",
    "widgetType" : "URI WidgetType",
    "openChoice" : true,
    "cardinality" : "0:*",
    "htmlName" : "%3Chttp%3A%2F%2Fjmvanel.free.fr%2Fjmv.rdf%23me%3E+%3Chttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2FschoolHomepage%3E+%3Chttp%3A%2F%2Fwww.ens-cachan.fr%2F%3E+.%0A",
    "valueLabel" : "http://www.ens-cachan.fr/",
    "isImage" : false
  }, 

{
    "subject" : "http://jmvanel.free.fr/jmv.rdf#me",
    "subjectLabel" : "Jean-Marc Vanel",
    "property" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
    "label" : "type",
    "comment" : "The subject is an instance of a class.",
    "mandatory" : false,
    "value" : "http://xmlns.com/foaf/0.1/Person",
    "type" : "http://www.w3.org/2000/01/rdf-schema#Class",
    "widgetType" : "URI WidgetType",
    "openChoice" : true,
    "cardinality" : "0:*",
    "htmlName" : "%3Chttp%3A%2F%2Fjmvanel.free.fr%2Fjmv.rdf%23me%3E+%3Chttp%3A%2F%2Fwww.w3.org%2F1999%2F02%2F22-rdf-syntax-ns%23type%3E+%3C%3E+.%0A",
    "valueLabel" : "Person",
    "isImage" : false
  }
]}

The htmlName JSON key above is, as the name implies, an HTML name parameter that can the used as a name in an HTML form, for the /save service. This name is an URL-encoded triple in N-Triple (Turtle) syntax. This way the server knows which original triple has been modified.

The /sparql-data web service

The /sparql-data service, like the /sparql and /sparql-form, takes in input a SPARQL query, as HTTP parameter query. Like the /form-data web service, the /sparql-data service returns a "rich" JSON data structure described above.

http://localhost:9000/sparql-data?query=PREFIX+foaf%3A+%3Chttp%3A%2F%2Fxmlns.com%2Ffoaf%2F0.1%2F%3E%0D%0ACONSTRUCT+{%3FP+foaf%3Aphone+%3FPH}WHERE+{GRAPH%20?G%20{%3FP+foaf%3Aphone+%3FPH+%3B+a+foaf%3APerson}}

The /files web service

The service /files allows to deploy static files in local files/ directory and sub-directories. This is where you will deploy your specific application files like example1.html above. The files are served like Apache does: dynamically added files, even during runtime, are served.

Using (X)HTML templates

Using plain Scala XHTML templates, or Play! style templates, it is possible to call the method corresponding to the /form web service: ApplicationFacade's method htmlFormElemJustFields() .

https://github.com/jmvanel/semantic_forms/blob/master/scala/forms/src/main/scala/deductions/runtime/services/ApplicationFacade.scala#L32

Customizing the form generator

Look at the code in the package deductions.runtime.html .

Other services

SPARQL 1.1 Graph Store HTTP Protocol

When you can, in your client application, generate RDF string content, the simplest way to store it in SF is the SPARQL 1.1 Graph Store HTTP Protocol with POST and PUT. The GET portion of the Graph Store HTTP Protocol is not implemented, but a SPARQL query allows you to do it:

 CONSTRUCT {? S? P? O} WHERE {GRAPH <graph_uri> {? S? P? O}}

The services are on relative URI's : /load, /sparql . For load, the URL prefix is /load?graph= , and
forms_play/dist/scripts/rload_wget.sh is an example script for loading a given TTL file to given load service in given graph (of user "bbb"). Here is an example of calling the script:

rload_wget.sh \
    ~/Documents/node69.csv.ttl http://localhost:9000/load user:bbb

The /load-uri service

There is also the convenient /load-uri service that loads content of given URI String into TDB in graph of same name. It can be used in shell scripts to load a bunch of URI's , e.g. : https://github.com/GrottoCenter/Karstlink-ontology/blob/master/scripts/load-grotto-entrances.sh

It is also used by the Scala script SPARQLquery2SFcacheApp, which, from a SPARQL query to another endpoint, loads URI's returned by the query into SF; in the end it is like if a user had pasted all those URI's and clicked on "Display". It amounts to make linked copies of all these semantic URI's into SF .

LDP protocol

There is also the W3C's LDP protocol with POST, PUT, GET that does as much and more than the Graph Store HTTP Protocol. The "plus" part is not implemented in SF (like listing a container). Let's say that the Graph Store HTTP Protocol sticks more to how SF works.

Lookup protocol

/lookup uses the same HTTP API as dbPedia lookup, but for a completion in the browser language, and by class (typically foaf:Person and foaf:Organization).

If one loads dbPedia data in SF (see how-to here: mirroring dbPedia ), it is possible to obtain a Lookup service compatible with original dbPedia lookup.