Skip to content

Commit

Permalink
Merge pull request #185 from ashleycaselli/53-shaclinfersh-hangs-when…
Browse files Browse the repository at this point in the history
…-ttl-contains-some-specific-owlimports

53 shaclinfersh hangs when ttl contains some specific owlimports
  • Loading branch information
ashleycaselli authored Jan 11, 2025
2 parents 486da09 + c0e31bc commit 49170c2
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 166 deletions.
6 changes: 3 additions & 3 deletions .docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ LABEL org.opencontainers.image.version=${VERSION}

# BUILD STAGE 1: install minimal Java environment + curl & zip for SHACL API

RUN apk add --no-cache binutils maven curl zip

# Create a custom Java runtime
RUN $JAVA_HOME/bin/jlink \
--add-modules java.base,java.compiler,java.desktop,java.management,java.naming,java.net.http,java.rmi,java.scripting,java.security.jgss,java.security.sasl,java.sql,java.xml.crypto,jdk.unsupported \
Expand All @@ -23,16 +25,14 @@ RUN $JAVA_HOME/bin/jlink \
--compress=2 \
--output /javaruntime

RUN apk add maven curl zip

# Compile with maven, extract binaries and copy into image
COPY . /app
RUN mvn versions:set -DnewVersion=${VERSION} && mvn package -Dmaven.test.skip=true
RUN unzip target/shacl-${VERSION}-bin.zip -d /app/

# BUILD STAGE 2: keep only Java and SHACL

FROM alpine:3.20.3
FROM alpine:3.21.2

ARG VERSION

Expand Down
8 changes: 8 additions & 0 deletions .docker/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ PARAMETER:
input to be validated (only .ttl format supported)
-shapesfile /data/myshapes.ttl [OPTIONAL]
shapes for validation (only .ttl format supported)
-maxiterations 1 [OPTIONAL] - default is 1
iteratively applies the inference rules until the maximum number of iterations is reached (or no new triples are inferred)
-validateShapes [OPTIONAL]
in case you want to include the metashapes (from the tosh namespace in particular)
-addBlankNodes [OPTIONAL]
adds the blank nodes to the validation report
-noImports [OPTIONAL]
disables the import of external ontologies
EOF
exit 1
fi
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Set up QEMU
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
uses: docker/setup-qemu-action@53851d14592bedcffcf25ea515637cff71ef929a # v3.3.0

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0

# inspired by https://github.com/reloc8/action-latest-release-version
- name: Get release version
Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:

- name: Build and push Docker image for x86 and arm64
id: build
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
uses: docker/build-push-action@b32b51a8eda65d6793cd0494a773d4f6bcef32dc # v6.11.0
with:
file: .docker/Dockerfile
push: true
Expand All @@ -93,7 +93,7 @@ jobs:
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: digests-${{ matrix.package }}
path: /tmp/digests/*
Expand Down Expand Up @@ -131,7 +131,7 @@ jobs:
merge-multiple: true

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0

- name: Extract metadata (tags, labels) for Docker
id: meta
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/maven-test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up JDK
uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
with:
distribution: ${{ matrix.distribution }}
java-version: ${{ matrix.java }}
Expand Down
40 changes: 22 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The binary distribution is:

`https://repo1.maven.org/maven2/org/topbraid/shacl/*VER*/shacl-*VER*-bin.zip`.

Two command line utilities are included: shaclvalidate (performs constraint validation) and shaclinfer (performs SHACL rule inferencing).
Two command line utilities are included: `shaclvalidate` (performs constraint validation) and `shaclinfer` (performs SHACL rule inferencing).

To use them, set up your environment similar to https://jena.apache.org/documentation/tools/ (note that the SHACL download includes Jena).

Expand All @@ -72,17 +72,13 @@ export SHACLROOT=/home/holger/shacl/shacl-1.4.3-bin/shacl-1.4.3/bin
export PATH=$SHACLROOT:$PATH
```

Both tools take the following parameters, for example:
After setting up the environment, you can run the command line utilities (i.e. validation) using the following command:

`shaclvalidate.bat -datafile myfile.ttl -shapesfile myshapes.ttl`
- Windows: `shaclvalidate.bat -datafile myfile.ttl -shapesfile myshapes.ttl`

where `-shapesfile` is optional and falls back to using the data graph as shapes graph.
Add -validateShapes in case you want to include the metashapes (from the tosh namespace in particular).
- Linux/Unix: `shaclvalidate.sh -datafile myfile.ttl -shapesfile myshapes.ttl`

For the shaclinfer tool, you can use the `-maxiterations` argument to apply SHACL rule inferencing multiple times; this will add inferred results back to the data graph to see if further triples can be inferred.
The tool will iterate until either (a) the maximum number of iterations is reached, or (b) no new triples are inferred. The flag is optional and defaults to `1` (single iteration).

Currently only Turtle (.ttl) files are supported.
Both tools (Windows, Linux) take the parameters described in the [Dockerfile Usage](#dockerfile-usage) section. **Currently, only Turtle (.ttl) files are supported.**

The tools print the validation report or the inferences graph to the output screen.

Expand Down Expand Up @@ -113,15 +109,23 @@ Any other command after `ghcr.io/topquadrant/shacl:1.4.3` will print the followi
Please use this docker image as follows:
docker run -v /path/to/data:/data ghcr.io/topquadrant/shacl:1.4.3 [COMMAND] [PARAMETERS]
COMMAND:
validate
to run validation
infer
to run rule inferencing
validate
to run validation
infer
to run rule inferencing
PARAMETERS:
-datafile /data/myfile.ttl [MANDATORY]
input to be validated (only .ttl format supported)
-shapesfile /data/myshapes.ttl [OPTIONAL]
shapes for validation (only .ttl format supported)
-datafile /data/myfile.ttl [MANDATORY]
input to be validated (only .ttl format supported)
-shapesfile /data/myshapes.ttl [OPTIONAL]
shapes for validation (only .ttl format supported)
-maxiterations 1 [OPTIONAL] - default is 1
iteratively applies the inference rules until the maximum number of iterations is reached (or no new triples are inferred)
-validateShapes [OPTIONAL]
in case you want to include the metashapes (from the tosh namespace in particular)
-addBlankNodes [OPTIONAL]
adds the blank nodes to the validation report
-noImports [OPTIONAL]
disables the import of external ontologies
```

If you'd like to build the image locally in an `x86` architecture, use:
Expand All @@ -134,4 +138,4 @@ If your architecture is `arm`, use:

```
docker build -f .docker/Dockerfile -t ghcr.io/topquadrant/shacl:1.4.3 --build-arg VERSION=1.4.3 --build-arg ARCH_BASE=amazoncorretto:11-alpine3.18-jdk .
```
```
8 changes: 4 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<ver.jena>5.2.0</ver.jena>
<ver.junit>4.13.2</ver.junit>
<ver.slf4j>1.7.36</ver.slf4j>
<ver.log4j2>2.20.0</ver.log4j2>
<ver.slf4j>2.0.16</ver.slf4j>
<ver.log4j2>2.24.3</ver.log4j2>
<java.version>17</java.version>
</properties>

Expand Down Expand Up @@ -99,7 +99,7 @@
<!-- Require a logging implementation -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>${ver.log4j2}</version>
<optional>true</optional>
</dependency>
Expand Down Expand Up @@ -210,7 +210,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.11.1</version>
<version>3.11.2</version>
<executions>
<execution>
<id>attach-javadocs</id>
Expand Down
151 changes: 73 additions & 78 deletions src/main/java/org/topbraid/shacl/tools/AbstractTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,6 @@
*/
package org.topbraid.shacl.tools;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.jena.ontology.OntDocumentManager;
import org.apache.jena.ontology.OntModel;
import org.apache.jena.ontology.OntModelSpec;
Expand All @@ -34,78 +29,78 @@
import org.topbraid.shacl.vocabulary.SH;
import org.topbraid.shacl.vocabulary.TOSH;

import java.io.*;

class AbstractTool {

private final static String DATA_FILE = "-datafile";

private final static String SHAPES_FILE = "-shapesfile";

private final static String MAX_ITERATIONS = "-maxiterations";


private OntDocumentManager dm = new OntDocumentManager();

private OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM);


AbstractTool() {

InputStream shaclTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/shacl.ttl");
Model shacl = JenaUtil.createMemoryModel();
shacl.read(shaclTTL, SH.BASE_URI, FileUtils.langTurtle);
shacl.add(SystemTriples.getVocabularyModel());
dm.addModel(SH.BASE_URI, shacl);

InputStream dashTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/dash.ttl");
Model dash = JenaUtil.createMemoryModel();
dash.read(dashTTL, SH.BASE_URI, FileUtils.langTurtle);
dm.addModel(DASH.BASE_URI, dash);

InputStream toshTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/tosh.ttl");
Model tosh = JenaUtil.createMemoryModel();
tosh.read(toshTTL, SH.BASE_URI, FileUtils.langTurtle);
dm.addModel(TOSH.BASE_URI, tosh);

spec.setDocumentManager(dm);
}

protected int getMaxIterations(String[] args) {
for(int i = 0; i < args.length - 1; i++) {
if(MAX_ITERATIONS.equals(args[i])) {
return Integer.parseInt(args[i + 1]);
}
}
return 1;
}

protected Model getDataModel(String[] args) throws IOException {
for(int i = 0; i < args.length - 1; i++) {
if(DATA_FILE.equals(args[i])) {
String dataFileName = args[i + 1];
OntModel dataModel = ModelFactory.createOntologyModel(spec);
File file = new File(dataFileName);
String lang = FileUtils.langTurtle;
dataModel.read(new FileInputStream(file), "urn:x:base", lang);
return dataModel;
}
}
System.err.println("Missing -datafile, e.g.: -datafile myfile.ttl");
System.exit(0);
return null;
}


protected Model getShapesModel(String[] args) throws IOException {
for(int i = 0; i < args.length - 1; i++) {
if(SHAPES_FILE.equals(args[i])) {
String fileName = args[i + 1];
OntModel model = ModelFactory.createOntologyModel(spec);
File file = new File(fileName);
String lang = FileUtils.langTurtle;
model.read(new FileInputStream(file), "urn:x:base", lang);
return model;
}
}
return null;
}
}
private final static String DATA_FILE = "-datafile";

private final static String SHAPES_FILE = "-shapesfile";

private final static String MAX_ITERATIONS = "-maxiterations";

protected final OntDocumentManager dm = new OntDocumentManager();

private OntModelSpec spec = new OntModelSpec(OntModelSpec.OWL_MEM);


AbstractTool() {

InputStream shaclTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/shacl.ttl");
Model shacl = JenaUtil.createMemoryModel();
shacl.read(shaclTTL, SH.BASE_URI, FileUtils.langTurtle);
shacl.add(SystemTriples.getVocabularyModel());
dm.addModel(SH.BASE_URI, shacl);

InputStream dashTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/dash.ttl");
Model dash = JenaUtil.createMemoryModel();
dash.read(dashTTL, SH.BASE_URI, FileUtils.langTurtle);
dm.addModel(DASH.BASE_URI, dash);

InputStream toshTTL = SHACLSystemModel.class.getResourceAsStream("/rdf/tosh.ttl");
Model tosh = JenaUtil.createMemoryModel();
tosh.read(toshTTL, SH.BASE_URI, FileUtils.langTurtle);
dm.addModel(TOSH.BASE_URI, tosh);

spec.setDocumentManager(dm);
}

protected int getMaxIterations(String[] args) {
for (int i = 0; i < args.length - 1; i++) {
if (MAX_ITERATIONS.equals(args[i])) {
return Integer.parseInt(args[i + 1]);
}
}
return 1;
}

protected Model getDataModel(String[] args) throws IOException {
for (int i = 0; i < args.length - 1; i++) {
if (DATA_FILE.equals(args[i])) {
return getModel(args, i);
}
}
System.err.println("Missing -datafile, e.g.: -datafile myfile.ttl");
System.exit(0);
return null;
}

protected Model getShapesModel(String[] args) throws IOException {
for (int i = 0; i < args.length - 1; i++) {
if (SHAPES_FILE.equals(args[i])) {
return getModel(args, i);
}
}
return null;
}

private Model getModel(String[] args, int i) throws FileNotFoundException {
String fileName = args[i + 1];
OntModel dataModel = ModelFactory.createOntologyModel(spec);
File file = new File(fileName);
String lang = FileUtils.langTurtle;
dataModel.read(new FileInputStream(file), "urn:x:base", lang);
return dataModel;
}

}
Loading

0 comments on commit 49170c2

Please sign in to comment.