Skip to content

Context History Entrepot

Alvaro Fides edited this page May 2, 2019 · 22 revisions

Table of Contents

Description

Also known as CHe, the Context History Entrepot stores all context events forwarded through the middleware into an ontological database in RDF statements format. Then it allows access to this data by several methods, like retrieving events stored from, to or between timestamps. Reasoning for maintaining the current status context is possible. Query for current context must be performed using a SPARQL query service, introducing the appropriate restrictions and filters in the query.

Features

This module covers the implementation of the following features:

  • Store context event
  • Retrieve event matching some criteria
  • Query/Modify context
    • Execute SPARQL query
    • Execute SPARQL UPDATE command
  • Automatically remove old context information
  • Model: Context history services for short-term storage provision
  • Encrypted storage

Artifacts

The following Maven artifacts, bundles and libraries from the Context repository are all related to the Context History Entrepot module.

Installation

To get the CHE working currently you only need to include the ctxt.che bundle in your running configuration, in addition to all its dependencies, which are the basic middleware (CHE uses Context and Service bus and data serialization), its ontology, and RDF4J storage engine. That would be:

  • ...Middleware bundles (with mw.data.serialization)...
  • org.universAAL.ontology/ont.che/x.y.z
  • org.universAAL.context/ctxt.che/x.y.z
  • org.universAAL.thirdparty/rdf4j-runtime-osgi-uaal/2.3.2 (a custom collection of RDF4J bundles, available in universAAL's third party repository)
The version of uAAL bundles is not shown, as this changes with every release. Another way to include the CHE is to use its composite bundle (scan-composite:mvn:org.universAAL.context/ctxt.che/x.y.0/composite) or the CHe Karaf feature (uAAL-ctxt.CHe) from the Context features.

Configuration

CHE is configured through a properties file called CHe.properties placed in folder ctxt.che in the configuration folder. The default values shown below are used if no configuration file is put. The properties that can be configured are:

Property Unit Default
RECYCLE.KEEP
Period of time from which context information is kept when auto-removing old events. A value of 2 means that only events older than 2 months will be removed when auto-removing Months 2
RECYCLE.DATE
Date at which auto-removal takes place. If the date has has passed when the CHE starts, it is scheduled at that day at the configured hour. When auto-removal happens, this property is automatically set to DATE+KEEP. Unix Timestamp-Milliseconds 0
RECYCLE.HOUR
Hour at which auto-removal takes place, when the DATE arrives. If DATE and HOUR have passed when CHE starts, it is scheduled for the next day. PM Hour 22
RECYCLE.DEBUG
For temporary debug purposes only. When true, it makes the CHE remove all its stored data when it is stopped. Set to false or remove option so that data is persisted across executions (this property will be removed in the final release). Boolean False
STORE.IMPL
Implementation of the Backend interface that wraps the storage engine for the CHE. Depending on its value it might need extra properties! See below. Class name, with package org. universAAL. context. che. database. impl. RDF4JBackend
STORE.LOGALIVE
Determines if Keep-alive events (SystemInfo - alive - true) are logged by the CHe or not. Boolean False
STORE.OVERWRITEOWL
Determines if the OWL file for each registered ontology in OntologyManagement should be recreated every time. It is useful to set it to true if ontologies are expected to change over time (although currently the data stored in the CHE would not change). Boolean False
STORE.TENANT
Enables tenant-awareness. Stores events assigning its origin tenant ID (scope) as RDF Dataset. Check Multitenancy section below for details. Boolean True

The STORE.IMPL parameter is the most important one as it can be used to select the implementation of the CHE and the store it uses (which we can call "the engine"). By default the CHe includes 2 implementations that can be selected, without having to add any new bundle. Each implementation may add new configuration parameters (shown below each one), and may require to install independent tools or engines. The default engines included with the CHe are:

  • org.universAAL.context.che.database.impl.RDF4JBackend: This is the default. It uses RDF4J Native Store based on the filesystem to store all arriving events and their data as statement triples. It provides good performance but does not perform any kind of reasoning other than Forward-Chaining.
Property Unit Default
STORE.LOCATION
Folder where the store files are placed. The path can be either absolute or relative. In the later case the root is taken as the "runner" folder where everything executes. There is no default but it is mandatory: set it or the CHE will fail to store events (an error is logged when CHE starts in that case). It is recommended that you set this to a common absolute path, otherwise you will have different stores in each runner folder. Unless that is what you want. Path None
STORE.PRELOAD
Iff present and true, this property enables the automatic preload of ontologies in CHE. Currently what it does is loading all OWL files in Turtle format placed in the configuration folder of CHE into the store. Notice that all registered ontologies are always converted to OWL files and placed there at the beginning, no matter what store implementation. WARNING! This must be enabled for extended features to work, such as the Profiling server! For advanced users: the file preload.properties in the config folder lists the preloaded ontologies. Setting one to false forces the reload at restart. Boolean None (understood as false)
  • org.universAAL.context.che.database.impl.RDF4JBackendWithConfidence: Does the same than the default, but every time an event arrives it checks its Confidence value and if it is lower than a threshold, it will only store the events statements but not the reified ones (If an event says User IsInPlace Room with confidence < threshold, then the statement User IsInPlace Room is not stored). In addition to STORE.LOCATION and STORE.PRELOAD shown above, it also has:
Property Unit Default
STORE.CONFIDENCE
Threshold for confidence value, 0 to 100, representing percentage. If the property is not present, which happens by deafult, it does not check confidence. Percentage None (understood as 0 = Disabled)

Extensions

You can add more implementations for CHe store that add new functionalities or different engines. To do so, you just need to add bundle-fragments known as CHE modules. Currently there is one module: ctxt.che.module.cardinality, available in https://github.com/universAAL/context/tree/master/ctxt.che.module.cardinality.

Its main goal is to add cardinality reasoning, as this feature is a rare find in most RDF stores out there. It only requires one extra library bundle to work: rdf4j.uaal.store in https://github.com/universAAL/context/tree/master/rdf4j.uaal.store, which by the way also enables encryption. So you need:

  • org.bouncycastle/jce.jdk13/144 (this is necessary also for rdf4j.uaal.store)
  • ...Middleware bundles...
  • org.universAAL.thirdparty/rdf4j-runtime-osgi-uaal/2.3.2
  • org.universAAL.ontology/ont.che/x.y.z
  • org.universAAL.context/rdf4j.uaal.store/x.y.z
  • org.universAAL.context/ctxt.che.module.cardinality/x.y.z
  • org.universAAL.context/ctxt.che/x.y.z
Just add those 2 extra bundles to your configuration and you can use it by choosing the right implementation in STORE.IMPL. Take into account that rdf4j.uaal.store is not a bundle but a jar, so you need to precede "wrap". The included implementations are:
  • org.universAAL.context.che.database.impl.RDF4JBackendCrd: Adds cardinality check to the default engine of CHE. If a property of a statement to be stored has maxCardinality=1 it will remove all previous values and store only the new one. Of course this does not check all possible values of cardinality, only if maxCardinality=1, which is the most useful and compliant with OWL Lite.
  • org.universAAL.context.che.database.impl.RDF4JBackendCrdCnf: Adds confidence check to the above, just like RDF4JBackendWithConfidence in the default CHE.
  • org.universAAL.context.che.database.impl.RDF4JBackendCrdClc: In addition to maxCardinality=1 check, it checks if the stored value is a multi-value closed collection. If so, it removes previous values and store only the new multi-value one.
  • org.universAAL.context.che.database.impl.RDF4JBackendCrdClcCnf: Adds the confidence check to the above.
  • org.universAAL.context.che.database.impl.RDF4J: An alternative that adds a check looking fro previous stored statements. If these were Closed Collections, it removes them, no matter the new value or cardinality.
  • org.universAAL.context.che.database.impl.RDF4JBackendCrdClc2Cnf: The same as the above but with confidence check.
The configuration values they use are the same than the default engines: STORE.LOCATION, STORE.PRELOAD and also STORE.CONFIDENCE if you choose a confidence implementation. In addition to this it also uses:
Property Unit Default
STORE.ENCRYPT
Determines whether the values stored in the engine would be encrypted. This option must be consistent: a store created with encryption enabled can only work properly if encryption is enable in subsequent executions. Performance is affected. Boolean None (understood as false)
rdf4j.uaal.store.keyfolder
Set in system.properties. Specify which configuration folder the encryption key is in Folder name mw.bus.model.osgi
rdf4j.uaal.store.cipher
Set in system.properties. Specify the cipher transformation used in encryption. String formatted for use by javax.crypto.Cipher.getInstance(String transformation) according to this document . If the string is not properly formatted, the default is used. Formatted String DES/ECB/PKCS5Padding

Mobile version

Mobile configuration options are not used: the mobile version of CHE is no longer supported. It was developed for an initial Android port of universAAL, now deprecated. The new Android port relies on direct connection to a node running the full version of CHE. However, the source code for this deprecated mobile version of CHE can still be obtained from https://github.com/universAAL/context/tree/master/ctxt.che.mobile. It may still be interesting as a light-weight mod if run in Karaf, but it is no longer being maintained. Use it at your own risk. It does not use any configuration. Start it and it will store any context event in a txt file called Mobile-Events.txt, in the configuration folder ctxt.che.mobile.

Multitenancy

After 3.3.1-SNAPSHOT the CHe can be configured to be tenant-aware (it is enabled by default). The RDF data of Context Events is stored assigning the origin Tenant ID/s (scope/s) as its RDF Dataset. If no tenant is set, no RDF Dataset is set (that's the default dataset). When requesting services of CHe, the Tenant of the originating request is used to define the dataset where to get data from - that is, the FROM clause of SPARQL. This is injected even if a query is requested without it. Therefore, only a request that does not have a tenant set can access the whole data stored.

In practice all this means that tenants will only be able to query their own data and no other, no matter what query they use. And only apps in the "server" side (no tenant ID) can access not only all the stored data, but also use the FROM clause to get data from specific tenants.

Custom Subscription

By default the CHe stores all events that travel through the Context Bus (if we don't count the LOGALIVE option). It does this with an "empty" Context Event Pattern. However, you can modify this behavior by defining a custom Context Event Pattern. To do so, write your Context Event Pattern in Turtle in a file called "subscription.ttl" and place it in the CHe configuration folder (next to CHe.properties). CHe will then only store events that match that pattern. Currently only one pattern is allowed, so you cannot combine them. If you want to change (or add, or remove) the pattern, you have to stop the CHe first.

Provided services

CHE provides a handful of services in the Service Bus so that applications can interact with the Context Store (If you want to store an event in the store, you don´t need to deal with services, they are all stored when forwarded through he Context Bus). The main services of CHE are for retrieving context events that match a given description, but there are a couple of them that allow for more flexibility and can be really helpful if you know SPARQL. Refer to the Javadoc of CHE for more information. For calling these from your app you will need to import the CHE ontology (ont.che).

  • GET EVENTS FROM/TO/BETWEEN TIMESTAMPS: These are 3 different services. All of them take a ContextEvent as input, which works as an incomplete description of the Event you want, but be warned! This ContextEvent that you must use to build the input is not the classic one. You must use the ContextEvent in the CHE ontology package org.universAAL.context.che.ontology. This one you can use it to leave properties null, as wildcards, so if you define an input ContextEvent with all properties null but with Subject "S", you will retrieve all events with subject "S". We encourage you to use the empty constructor and then individual setters if you plan to set them null. The timestamp inputs you can add to this service work as time delimiters. For instance if you define inputs for both TIMESTAMP FROM and TIMESTAMP TO, you will get matching events that were stored between those two instants.
  • GET EVENTS BY SPARQL: With this you can retrieve events that match a custom direct SPARQL Query, if you think the above method is too complex... You just need to make sure that the query is a SELECT query that will return ContextEvents in a variable "?c", that is, the query starts with "SELECT ?c WHERE...".
  • SPARQL QUERY: This is the most powerful service. You can perform any kind of SPARQL query passed as a String input, and recover a serialized String result, that of course you will have to process on your own. Unless the result output tells you otherwise, you can perform any kind of SPARQL query. However the serialized result will be formatted in different ways:
    • SELECT: Results are serialized in RDF XML results format.
    • ASK: Result is the string "true" or "false".
    • CONSTRUCT: Results are serialized in Turtle, so you can use MessageContentSerializer to turn it back into uAAL code.
    • DESCRIBE: Like above, in Turtle.
    • UPDATE: You can even perform SPARQL UPDATE operations (expect security measures to be applied in the future). The result is the String "true" if the update could be performed.
If you are interested in implementing your own additional short-term context history module, you will have to use the Context History service ontology. It is available in the CHE ontology artifact, in the package org.universAAL.context.che.ontology. It has concepts that allow you to define context history services restricted to a delimited time period.

Remember that for more details on how to build you requests or services you can refer to the Javadoc of CHe.

Code samples

  • Service request for GET EVENTS FROM TIMESTAMP
 ServiceRequest getEvents = new ServiceRequest(
    new ContextHistoryService(null), null);
  MergedRestriction r = MergedRestriction.getFixedValueRestriction(
    ContextHistoryService.PROP_MANAGES, matchEvent);
    getEvents.getRequestedService().addInstanceLevelRestriction(r,
    new String[] { ContextHistoryService.PROP_MANAGES });
 MergedRestriction tstr1 = MergedRestriction.getFixedValueRestriction(
     ContextHistoryService.PROP_TIMESTAMP_FROM,
     new Long(tstFrom));
 getEvents.getRequestedService().addInstanceLevelRestriction(tstr1,
     new String[] { ContextHistoryService.PROP_TIMESTAMP_FROM });
 getEvents.addSimpleOutputBinding(new ProcessOutput(
    OUTPUT_LIST_OF_EVENTS), new PropertyPath(null, false,
    new String[] { ContextHistoryService.PROP_MANAGES })
    .getThePath());
  • Service request for GET EVENTS BY SPARQL
 ServiceRequest getQuery = new ServiceRequest(new ContextHistoryService(
    null), null);
 MergedRestriction r = MergedRestriction.getFixedValueRestriction(
    ContextHistoryService.PROP_PROCESSES, query);
 getQuery.getRequestedService().addInstanceLevelRestriction(r,
    new String[] { ContextHistoryService.PROP_PROCESSES });
 getQuery.addSimpleOutputBinding(
    new ProcessOutput(OUTPUT_LIST_OF_EVENTS), new PropertyPath(
        null, false,
        new String[] { ContextHistoryService.PROP_MANAGES })
        .getThePath());
  • Service request for SPARQL QUERY
 ServiceRequest getQuery = new ServiceRequest(new ContextHistoryService(
    null), null);
 MergedRestriction r = MergedRestriction.getFixedValueRestriction(
    ContextHistoryService.PROP_PROCESSES, query);
 getQuery.getRequestedService().addInstanceLevelRestriction(r,
    new String[] { ContextHistoryService.PROP_PROCESSES });
 getQuery.addSimpleOutputBinding(
    new ProcessOutput(OUTPUT_RESULT_STRING), new PropertyPath(null,
        true,
        new String[] { ContextHistoryService.PROP_RETURNS })
        .getThePath());

Context events

The context history entrepot does not provide any context information through the context bus. It just consumes all of it by default.

Code samples

  • The default subscription pattern of the CHE (can be changed as described in Custom Subscription)
 new ContextEventPattern[] { new ContextEventPattern() }

User interaction

The context history entrepot does not provide any user interface.