Skip to content
This repository was archived by the owner on Feb 15, 2024. It is now read-only.

Commit f6bae44

Browse files
author
Matthias Böckmann
committed
Adding initial version of Validator
1 parent 022256e commit f6bae44

9 files changed

Lines changed: 2400 additions & 1 deletion

File tree

dataformat-jsonld/src/test/java/io/adminshell/aas/v3/model/dataformat/jsonld/SerializerTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414

1515
public class SerializerTest {
1616

17-
//TODO: Classes have no IDs, so the @id is missing
1817
//TODO: Optional: Prefixes instead of full URIs
1918
//TODO: Optional: Do not serialize empty collections
2019

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<module>dataformat-json</module>
1414
<module>dataformat-xml</module>
1515
<module>dataformat-jsonld</module>
16+
<module>validator</module>
1617
</modules>
1718
<properties>
1819
<revision>1.0.2-SNAPSHOT</revision>

validator/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>dataformat-parent</artifactId>
7+
<groupId>io.admin-shell.aas</groupId>
8+
<version>${revision}</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>validator</artifactId>
13+
14+
<properties>
15+
<maven.compiler.source>12</maven.compiler.source>
16+
<maven.compiler.target>12</maven.compiler.target>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>io.admin-shell.aas</groupId>
22+
<artifactId>dataformat-jsonld</artifactId>
23+
<version>${revision}</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>org.apache.jena</groupId>
27+
<artifactId>jena-shacl</artifactId>
28+
<version>${jena.version}</version>
29+
</dependency>
30+
<dependency>
31+
<groupId>junit</groupId>
32+
<artifactId>junit</artifactId>
33+
<version>${junit.version}</version>
34+
<scope>test</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.slf4j</groupId>
38+
<artifactId>slf4j-simple</artifactId>
39+
<version>1.7.30</version>
40+
<scope>test</scope>
41+
</dependency>
42+
</dependencies>
43+
44+
</project>
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package io.adminshell.aas.v3.model.validator;
2+
3+
import io.adminshell.aas.v3.dataformat.jsonld.Serializer;
4+
import org.apache.jena.graph.compose.Union;
5+
import org.apache.jena.rdf.model.Model;
6+
import org.apache.jena.rdf.model.ModelFactory;
7+
import org.apache.jena.riot.RDFLanguages;
8+
import org.apache.jena.riot.RiotException;
9+
import org.apache.jena.shacl.Shapes;
10+
import org.apache.jena.shacl.ValidationReport;
11+
import org.apache.jena.shacl.validation.ReportEntry;
12+
import org.apache.jena.util.FileUtils;
13+
import org.slf4j.LoggerFactory;
14+
15+
import java.io.*;
16+
import java.nio.charset.StandardCharsets;
17+
import java.util.HashMap;
18+
import java.util.stream.Collectors;
19+
20+
21+
public class ShaclValidator implements Validator{
22+
23+
private final static org.slf4j.Logger logger = LoggerFactory.getLogger(ShaclValidator.class);
24+
private final Shapes shapes;
25+
private final Model ontologyModel;
26+
27+
private static ShaclValidator validator;
28+
29+
private static final Serializer serializer = new Serializer();
30+
31+
32+
/**
33+
* Function to get the validator object. Initializes if it does not exist yet. Note that initialization might take a long time and should be done prior to incoming messages
34+
* @return ShaclValidator object to validate RDF
35+
*/
36+
public static ShaclValidator getInstance() {
37+
if(validator == null)
38+
{
39+
validator = new ShaclValidator();
40+
}
41+
return validator;
42+
}
43+
44+
/**
45+
* Function to validate Objects against SHACL shapes.
46+
* @param obj Object to be validated alongside the information model against the shape files
47+
*/
48+
@Override
49+
public void validate(Object obj) throws ValidationException {
50+
//Perform the validation
51+
//The data graph is the information model plus the message, hence let's create a Union graph
52+
try {
53+
ValidationReport report = validateGetReport(obj);
54+
55+
if (!report.conforms()) {
56+
throw new ValidationException(report.getEntries().stream().map(ReportEntry::toString).collect(Collectors.joining()));
57+
}
58+
}
59+
catch (IOException e)
60+
{
61+
throw new ValidationException("Validation process could not be completed.", e);
62+
}
63+
}
64+
65+
/**
66+
* Function to validate Objects against SHACL shapes.
67+
* @param obj Object to be validated alongside the information model against the shape files
68+
*/
69+
public ValidationReport validateGetReport(Object obj) throws IOException {
70+
String rdfSerialization;
71+
72+
//Turn object into JSON-LD
73+
rdfSerialization = serializer.serialize(obj, RDFLanguages.JSONLD, new HashMap<>());
74+
75+
ShaclValidator val = getInstance();
76+
//Ontology is already loaded. Now we need to parse the message.
77+
Model messageModel = ModelFactory.createDefaultModel();
78+
79+
//Read JSON-LD String into a model
80+
try {
81+
messageModel.read(new ByteArrayInputStream(rdfSerialization.getBytes(StandardCharsets.UTF_8)), null, "JSONLD");
82+
}
83+
catch (RiotException e)
84+
{
85+
throw new IOException("The message is no valid JSON-LD and could therefore not be checked for information model compliance.", e);
86+
}
87+
88+
//Perform the validation
89+
//The data graph is the information model plus the message, hence let's create a Union graph
90+
return org.apache.jena.shacl.ShaclValidator.get().validate(val.shapes, new Union(messageModel.getGraph(), val.ontologyModel.getGraph()));
91+
}
92+
93+
94+
/**
95+
* Function to explicitly initialize the ShaclValidator object. This can be used to avoid long initialization times when a message comes in
96+
*/
97+
@Override
98+
public void initialize() {
99+
if(validator == null)
100+
{
101+
validator = new ShaclValidator();
102+
}
103+
}
104+
105+
106+
private ShaclValidator() {
107+
logger.info("Initializing SHACL shapes.");
108+
109+
//Initialize an empty model into which we will be loading the shapes
110+
Model shapesModel = ModelFactory.createDefaultModel();
111+
112+
/*
113+
//Use resources from zip file
114+
//TODO: Will they be compressed?
115+
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("validation.zip");
116+
117+
//Stream this to some temporary file which will be deleted after program exit
118+
if (inputStream == null)
119+
throw new IOException("Failed to retrieve validation.zip from resources.");
120+
121+
File inputStreamToFile = File.createTempFile("validation_zip_file", null);
122+
inputStreamToFile.deleteOnExit();
123+
124+
Files.copy(inputStream, inputStreamToFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
125+
ZipFile zipFile = new ZipFile(inputStreamToFile);
126+
Enumeration<? extends ZipEntry> entries = zipFile.entries();
127+
128+
while (entries.hasMoreElements()) {
129+
shapesModel.read(zipFile.getInputStream(entries.nextElement()), null, FileUtils.langTurtle);
130+
}
131+
*/
132+
//shapesModel.read(Files.readString(Path.of("src/main/resources/shapes.ttl")));
133+
134+
135+
//All loaded, let's parse!
136+
//shapes = Shapes.parse(shapesModel);
137+
InputStream shapesInputStream = getClass().getClassLoader().getResourceAsStream("shapes.ttl");
138+
InputStream ontologyInputStream = getClass().getClassLoader().getResourceAsStream("ontology.ttl");
139+
shapesModel.read(shapesInputStream, null, FileUtils.langTurtle);
140+
shapes = Shapes.parse(shapesModel);
141+
ontologyModel = ModelFactory.createDefaultModel();
142+
143+
logger.info("Loading ontology");
144+
145+
146+
//Load the input stream into the ontology model
147+
ontologyModel.read(ontologyInputStream, null, FileUtils.langTurtle);
148+
logger.info("Initialization of SHACL shapes complete.");
149+
}
150+
151+
152+
153+
}
154+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.adminshell.aas.v3.model.validator;
2+
3+
public class ValidationException extends Exception {
4+
5+
public ValidationException(String msg) {
6+
super(msg);
7+
}
8+
9+
public ValidationException(String msg, Throwable err) {
10+
super(msg, err);
11+
}
12+
13+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package io.adminshell.aas.v3.model.validator;
2+
3+
import java.io.IOException;
4+
5+
public interface Validator {
6+
7+
void validate(Object obj) throws ValidationException;
8+
9+
void initialize();
10+
11+
}

0 commit comments

Comments
 (0)