Building Applications with the EulerGUI + Déductions framework

© Jean-Marc Vanel - $Date: 2012-07-30$ - under Creative Commons License

TOC

Introduction

This is a translation and enhancement of the seminal (!) post in french group deductions-fr "Applications exemples".

This document explains how to build business applications with the software framework

Here are some general tips :

  1. start from an existing ontology if there is one (see Finding ontologies on the Web, Famous ontologies), and add the necessary property and classes
  2. if necessary, develop and importer (connector) to convert and/or import existing data into semantic web formats and database (see Data and model sources in EulerGUI , Import to N3/RDF )
  3. add business and application rules: constraints and constructive rules; to do so they can be written in controlled English via ACE View or ACEWiki, or directly in N3, or a combination of both
  4. leverage on a simple semantics for user interaction, based on these concepts: CRUD (Create, Read, Update, Remove), log, statistics, current tasks
  5. as a first step, generate a minimal GUI, perhaps in command line;
  6. separate data into different files in an EulerGUI project : ontology, business rules, applicatives rules;

Samples applications will be put in a directory samples/ (a Maven sub-project) in EulerGUI working directory.

Links:

From formal english to application

See Working with controlled (formal) english through ACE View .

First let me quote the commonKADS site :

Knowledge is to be modelled at a conceptual level, in a way independent of specific computational construct.

The steps (using Attempto command line , ACE View (Protégé), or AceWiki ):

  1. just think out loud and write rules and data model (some examples here )
  2. get the syntax right
  3. ensure with paraphrase in Attempto that the semantics is what is intented
  4. check vocabulary coherence and check for synomyms, and generalisations
  5. try to align properties and classes with a well known ontology (FOAF, DC, etc)
  6. write a test with EulerGUI to check the desired inferences
  7. design the applicative architecture (choose inference engine, populate the user RDF graph, extract inference results or use callback/listeners, ...); TODO elaborate this
  8. write applicative test, e.g with Jemmy for Swing
  9. implement the bridges between rule base and platform services ( database, GUI, network, etc )

Remarks

User interaction piloted by rules

The user interaction is based on a simple semantics for user interaction, involving these concepts: CRUD data manipulations (CReate, Update, Remove), plus log, statistics, current tasks, represented by these imperative properties :

Design reusing the swing-rules3 rule base

For the data manipulations, it's possible to reuse the swing-rules3 rule base (see Rule based Swing applications), with small modification to make it more flexible.

The swing-rules3 rule base gathers all properties that are reachable from an RDF node, taking in account class assertions, domains, ranges , etc. However user interaction needs more flexibility:

  1. having input fields that do not necessary coincide with the domain ontologies
  2. verification of user input,
  3. different and specific widgets.

For point 1, the trick is to design a class specific for the user interaction, plus rules that interpret the user interaction data and transform it into regular ontolgy data that is stored in the Knowledge Base.

For point 2, we would like to write verification as pure domain rules, like this :

@prefix ded: <http://deductions.sf.net/owl/events#> .
@prefix    : <http://jmvanel.free.fr/ontology/examples/person#> .
# <http://deductions.sf.net/owl/events#exception>
{ ?P a :Person .
  ?P :name "bush" .
} => {
  ?E a ded:Exception
  ; rdfs:label " is already retired!"
  ; rdf:subject ?P
  ; rdf:predicate :name .
} .

Something close to this used to work in the very first version of the framework, where the focus lost listener was implemented 100% in Java.

It is possible to add in the Swing rule base rules to match ded:Exception, retrieve the associated input field widget, and reestablish the former value in the widget and the KB.

For point 3, the current framework with embedded Java objects allows to instatiate any custom widget , add it to relevant panel, and add it as a listener.

NOTE:

Currently, the infered GUI is only partly MVC (Model-View-Controler). The controler is provided by the rule base. However, the Views do not (yet) listen to the Model ( which is, for this framework , the RDF Knowledge Base).

How to reuse the swing-rules3 rule base

A typical inference flow :

application => main window and panels for data manipulations, log, statistics, current tasks
user => create Form From Class ?C
  => create new RDF ID
  => create input widget for new RDF ID in data manipulations panel

The user action to create a Form From Class ?C can be triggered through a specific button or menu entry, whose callback simply asserts the imperative RDF in the KB. Or, for the developer, the imperative RDF can be entered in the N3 shell (N3 command line). Or it can simply be asserted in an N3 source like in the example project person-app.n3p :

# dynamically create platform independant application widgets
#------------------------------------------------------------
# create application Window
_:APPINST app:hasWindow _:WINDOW .
# create a form for a new class instance
:FORM gui:createFormFromClass :Person .
# add the form in application Window
_:WINDOW gui:components :FORM .

Having set an application window like above, GUI content can be added from pure business conditions , e.g. :

{ <pure business condition> } => {
   _:label a gengui:Label
      ; java:text "label added through N3" .
   :FORM gui:components _:label .
} .

In the example project person-app.n3p , if you type JMV in the "name" input field, this text will be added in the generated GUI : "He's a nice guy." .

See also: N3 rules triggering Java actions .

To know exactly what is implemented and works in Java + N3 mixing, look at the test class BasicRuntimeTest .

Data manipulations ontology

Beyond reusing the swing-rules3 rule base, even more flexibility will be gained with Data manipulations ontology (WORK IN PROGRESS).

I propose to model declaratively user interaction with the concept of user transaction. A user transaction is a list of data manipulations.

A data manipulation is an elementary input from the user. There are four kinds of data manipulations for the two kinds of properties as defined in OWL (Properties "object" and properties "datatype"):

  1. add RDF statement ,
  2. modify RDF statement,
  3. remove RDF statement,
  4. create a new RDF identifier with its type.

A data manipulation is associated with a subject and property in the OWL / RDF sense. Modification and destruction have in addition an object in RDF sense .

For example, adding a statement corresponds to the addition of an identifier article in a commercial order.

A creation of a new RDF identifier is the creation of a new bank account, for later making money transfers with it.

When you create a transaction via a rule, there is every possibility of the N3 language to add additional conditions. For example adding an ID article in a commercial order, we can restrict proposals to categories corresponding to the user's interests, or its past orders.

It remains only to create implementations for the language to user interaction through rules mixing Java and pure business. One can consider several implementations: Swing, GWT, SWT, command, etc..

To begin, one must write this small N3 vocabulary . We'll put it in the project Deductions in owl/user_interaction.owl.n3

Here is an example of using the app:hasLogEntry predicate . Assume we are in the RHS of a rule (the consequent) . So a variable ?CONTACT, non existent in the left side of the rule (the antecedent) is a creation of a new identifier.

@prefix app: <http://eulergui.sf.net/ontology/application.owl.n3#>.
:myApp app:log [ "Ajout d'un nouveau contact"@fr ?CONTACT ].
?CONTACT a :Contact. 

Here is an example of using the app:hasStatistic predicate:

@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix e: <http://eulersharp.sourceforge.net/2003/03swap/log-rules#> .
{ _:d e:findall( ?CONTACT { ?CONTACT a :Contact } ?CONTACTS ).
   ?CONTACTS math:memberCount ?NB_CONTACT.
} => {
  ?S a app:Statistic.
  ?S rdfs:label "Nombre de contacts: "@fr .
  ?S app:information ?NB_CONTACT .
  :myApp app:hasStatistic ?S.
}. 

Delegate computations to Java in N3 rule engine

Suppose an ontology like this:

AppartmentOrHouse <>--- Room <>--- ClosedCurve <>--- Point

N3 rules are well suited to express commercial or regulation rules, like determining a category, or estimating prices. However, It would not be convenient for complex mathematical computations, for example to express in N3 the computation of the surface of a room.

So these computations would be written in a imperative language, Java for instance. Then there are two implementation questions:

  1. how to ease access to the RDF data for the Java code ?
  2. how to give the N3 rule engine access to the results of the Java code ?

For point 1, we currently have nothing smart implemented, just access to the interface ITripleStoreRETE extending ITripleStore.

To be available to Java methods through the rule base, the triple Store is added to itself as URI eg:STORAGE .

Not only computations can be delegated to to Java, but also GUI's. We have developped GUI Swing components for Semantic Web display and edition: N3TableModel, TripleComboBoxes.

But there are hints that need to be generalised, see Calling user Java code , Extension points with interfaces . Also there several projects for RDF to Java mapping frameworks, see Experience using Java-based frameworks for RDF-to-POJO (and vice versa) mapping, rdf2java, Tripresso .

For point 2, here is the recommended idiom:

# First, assign a Java class to an RDF resource:
{ ?CC a re:ClosedCurve.
} => {
  ?CC a java:geometry-ClosedCurve .
}.

# Then, the computation is triggered, and the result goes into the RDF KB:
{ ?CC a re:ClosedCurve. # facultative
  ?CC javam:getSurface ?SURFACE.
} => {
  ?CC re:hasSurface ?SURFACE. }.