Skip to content

Commit

Permalink
feat: add SHACL processor
Browse files Browse the repository at this point in the history
  • Loading branch information
jenspots committed May 24, 2024
1 parent 73f1f82 commit 2db38c4
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 1 deletion.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ A proof-of-concept implementation of a Kotlin-based JVM runner. Currently, this

This runner includes a set of standard processors that can be used directly by the end user without the need for additional dependencies. These processors also serve as a reference for processor developers. The implementation can be found [here](src/main/kotlin/std).

##### RDF Utilities

Interact with RDF data.

| Processor | Description |
|-------------------------------------------------------------|--------------------------------|
| [`jvm:RDFValidator`](./src/main/kotlin/std/RDFValidator.kt) | Validate RDF data using SHACL. |


##### Network Utilities

These processors interact with the network.
Expand All @@ -20,7 +29,7 @@ These processors interact with the network.

##### File Utilities

These processors interact with the local file system.
Fetch and write data from and to the local file system.

| Processor | Description |
|---------------------------------|------------------------------------------------------------------------|
Expand Down
75 changes: 75 additions & 0 deletions src/main/kotlin/std/RDFValidator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package technology.idlab.std

import bridge.Reader
import bridge.Writer
import java.io.ByteArrayOutputStream
import java.io.File
import org.apache.jena.graph.Graph
import org.apache.jena.rdf.model.ModelFactory
import org.apache.jena.shacl.ShaclValidator
import technology.idlab.extensions.readModelRecursively
import technology.idlab.logging.Log
import technology.idlab.runner.Processor

class RDFValidator(args: Map<String, Any>) : Processor(args) {
/** Default values. */
private val errorIsFatalDefault = false
private val printReportDefault = false

/** Arguments. */
private val errorIsFatal = this.getOptionalArgument<Boolean>("error_is_fatal")
private val printReport = this.getOptionalArgument<Boolean>("print_report")
private val input = this.getArgument<Reader>("input")
private val output = this.getArgument<Writer>("output")

/** Runtime fields. */
private val shapes: Graph
private val model = ModelFactory.createDefaultModel()
private val validator = ShaclValidator.get()

// Initialize the shape graph and validator.
init {
val path = this.getArgument<String>("shapes")
val file = File(path)
val shapesModel = file.readModelRecursively()
this.shapes = shapesModel.graph
}

/** Read incoming data, validate it, and output it. */
override fun exec() {
while (true) {
// Read incoming data.
val res = input.readSync()
if (res.isClosed()) {
break
}

// Parse as a model.
Log.shared.assert(model.isEmpty, "Model should be empty.")
model.read(res.value.toString())

// Validate the model.
val report = validator.validate(shapes, model.graph)
if (!report.conforms()) {
if (printReport.orElse(printReportDefault)) {
val out = ByteArrayOutputStream()
report.model.write(out, "TURTLE")
Log.shared.info(out.toString())
}

if (errorIsFatal.orElse(errorIsFatalDefault)) {
Log.shared.fatal("Validation error is fatal.")
}
}

// Reset model for next invocation.
model.removeAll(null, null, null)

// Propagate to the output.
output.pushSync(res.value)
}

// Close the output.
output.close()
}
}
44 changes: 44 additions & 0 deletions src/main/resources/std/rdf_validator.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
@prefix jvm: <https://w3id.org/conn/jvm#>.
@prefix owl: <http://www.w3.org/2002/07/owl#>.
@prefix sh: <http://www.w3.org/ns/shacl#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.

<> owl:imports <../pipeline.ttl>.

jvm:RDFValidator a jvm:Processor;
jvm:file <../../kotlin/std/RDFValidator.kt>;
jvm:language "Kotlin".

[] a sh:NodeShape;
sh:targetClass jvm:RDFValidator;
sh:property [
sh:path jvm:shapes;
sh:name "shapes";
sh:datatype xsd:string;
sh:minCount 1;
sh:maxCount 1;
], [
sh:path jvm:error_is_fatal;
sh:name "error_is_fatal";
sh:datatype xsd:boolean;
sh:maxCount 1;
], [
sh:path jvm:print_report;
sh:name "print_report";
sh:datatype xsd:boolean;
sh:maxCount 1;
], [
sh:path jvm:input;
sh:name "input";
sh:class jvm:ChannelReader;
sh:minCount 1;
sh:maxCount 1;
], [
sh:path jvm:output;
sh:name "output";
sh:class jvm:ChannelWriter;
sh:minCount 1;
sh:maxCount 1;
];
sh:closed true;
sh:ignoredProperties (rdf:type).

0 comments on commit 2db38c4

Please sign in to comment.